Module std::old_ioUnstable
[-] [+]
[src]
I/O, including files, networking, timers, and processes
Warning: This module is currently called
old_io
for a reason! The module is currently being redesigned in a number of RFCs. For more details follow the RFC repository in connection with RFC 517 or follow some of these sub-RFCs
std::io
provides Rust's basic I/O types,
for reading and writing to files, TCP, UDP,
and other types of sockets and pipes,
manipulating the file system, spawning processes.
Examples
Some examples of obvious things you might want to do
Read lines from stdin
fn main() { use std::old_io as io; let mut stdin = io::stdin(); for line in stdin.lock().lines() { print!("{}", line.unwrap()); } }use std::old_io as io; let mut stdin = io::stdin(); for line in stdin.lock().lines() { print!("{}", line.unwrap()); }
Read a complete file
fn main() { use std::old_io::File; let contents = File::open(&Path::new("message.txt")).read_to_end(); }use std::old_io::File; let contents = File::open(&Path::new("message.txt")).read_to_end();
Write a line to a file
fn main() { #![allow(unused_must_use)] use std::old_io::File; let mut file = File::create(&Path::new("message.txt")); file.write_all(b"hello, file!\n"); drop(file); ::std::old_io::fs::unlink(&Path::new("message.txt")); }use std::old_io::File; let mut file = File::create(&Path::new("message.txt")); file.write_all(b"hello, file!\n");
Iterate over the lines of a file
fn main() { use std::old_io::BufferedReader; use std::old_io::File; let path = Path::new("message.txt"); let mut file = BufferedReader::new(File::open(&path)); for line in file.lines() { print!("{}", line.unwrap()); } }use std::old_io::BufferedReader; use std::old_io::File; let path = Path::new("message.txt"); let mut file = BufferedReader::new(File::open(&path)); for line in file.lines() { print!("{}", line.unwrap()); }
Pull the lines of a file into a vector of strings
fn main() { use std::old_io::BufferedReader; use std::old_io::File; let path = Path::new("message.txt"); let mut file = BufferedReader::new(File::open(&path)); let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect(); }use std::old_io::BufferedReader; use std::old_io::File; let path = Path::new("message.txt"); let mut file = BufferedReader::new(File::open(&path)); let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();
Make a simple TCP client connection and request
fn main() { #![allow(unused_must_use)] use std::old_io::TcpStream; // connection doesn't fail if a server is running on 8080 // locally, we still want to be type checking this code, so lets // just stop it running (#11576) if false { let mut socket = TcpStream::connect("127.0.0.1:8080").unwrap(); socket.write_all(b"GET / HTTP/1.0\n\n"); let response = socket.read_to_end(); } }use std::old_io::TcpStream; let mut socket = TcpStream::connect("127.0.0.1:8080").unwrap(); socket.write_all(b"GET / HTTP/1.0\n\n"); let response = socket.read_to_end();
Make a simple TCP server
fn main() { } fn foo() { #![allow(dead_code)] use std::old_io::{TcpListener, TcpStream}; use std::old_io::{Acceptor, Listener}; use std::thread; let listener = TcpListener::bind("127.0.0.1:80"); // bind the listener to the specified address let mut acceptor = listener.listen(); fn handle_client(mut stream: TcpStream) { // ... &mut stream; // silence unused mutability/variable warning } // accept connections and process them, spawning a new tasks for each one for stream in acceptor.incoming() { match stream { Err(e) => { /* connection failed */ } Ok(stream) => { thread::spawn(move|| { // connection succeeded handle_client(stream) }); } } } // close the socket server drop(acceptor); }use std::old_io::{TcpListener, TcpStream}; use std::old_io::{Acceptor, Listener}; use std::thread; let listener = TcpListener::bind("127.0.0.1:80"); // bind the listener to the specified address let mut acceptor = listener.listen(); fn handle_client(mut stream: TcpStream) { // ... } // accept connections and process them, spawning a new tasks for each one for stream in acceptor.incoming() { match stream { Err(e) => { /* connection failed */ } Ok(stream) => { thread::spawn(move|| { // connection succeeded handle_client(stream) }); } } } // close the socket server drop(acceptor);
Error Handling
I/O is an area where nearly every operation can result in unexpected errors. Errors should be painfully visible when they happen, and handling them should be easy to work with. It should be convenient to handle specific I/O errors, and it should also be convenient to not deal with I/O errors.
Rust's I/O employs a combination of techniques to reduce boilerplate while still providing feedback about errors. The basic strategy:
- All I/O operations return
IoResult<T>
which is equivalent toResult<T, IoError>
. TheResult
type is defined in thestd::result
module. - If the
Result
type goes unused, then the compiler will by default emit a warning about the unused result. This is becauseResult
has the#[must_use]
attribute. - Common traits are implemented for
IoResult
, e.g.impl<R: Reader> Reader for IoResult<R>
, so that error values do not have to be 'unwrapped' before use.
These features combine in the API to allow for expressions like
File::create(&Path::new("diary.txt")).write_all(b"Met a girl.\n")
without having to worry about whether "diary.txt" exists or whether
the write succeeds. As written, if either new
or write_line
encounters an error then the result of the entire expression will
be an error.
If you wanted to handle the error though you might write:
fn main() { #![allow(unused_must_use)] use std::old_io::File; match File::create(&Path::new("diary.txt")).write_all(b"Met a girl.\n") { Ok(()) => (), // succeeded Err(e) => println!("failed to write to my diary: {}", e), } ::std::old_io::fs::unlink(&Path::new("diary.txt")); }use std::old_io::File; match File::create(&Path::new("diary.txt")).write_all(b"Met a girl.\n") { Ok(()) => (), // succeeded Err(e) => println!("failed to write to my diary: {}", e), }
So what actually happens if create
encounters an error?
It's important to know that what new
returns is not a File
but an IoResult<File>
. If the file does not open, then new
will simply
return Err(..)
. Because there is an implementation of Writer
(the trait
required ultimately required for types to implement write_line
) there is no
need to inspect or unwrap the IoResult<File>
and we simply call write_line
on it. If new
returned an Err(..)
then the followup call to write_line
will also return an error.
try!
Explicit pattern matching on IoResult
s can get quite verbose, especially
when performing many I/O operations. Some examples (like those above) are
alleviated with extra methods implemented on IoResult
, but others have more
complex interdependencies among each I/O operation.
The try!
macro from std::macros
is provided as a method of early-return
inside Result
-returning functions. It expands to an early-return on Err
and otherwise unwraps the contained Ok
value.
If you wanted to read several u32
s from a file and return their product:
use std::old_io::{File, IoResult}; fn file_product(p: &Path) -> IoResult<u32> { let mut f = File::open(p); let x1 = try!(f.read_le_u32()); let x2 = try!(f.read_le_u32()); Ok(x1 * x2) } match file_product(&Path::new("numbers.bin")) { Ok(x) => println!("{}", x), Err(e) => println!("Failed to read numbers!") }
With try!
in file_product
, each read_le_u32
need not be directly
concerned with error handling; instead its caller is responsible for
responding to errors that may occur while attempting to read the numbers.
Reexports
pub use self::SeekStyle::*; |
pub use self::FileMode::*; |
pub use self::FileAccess::*; |
pub use self::IoErrorKind::*; |
pub use self::stdio::stdin; |
pub use self::stdio::stdout; |
pub use self::stdio::stderr; |
pub use self::stdio::print; |
pub use self::stdio::println; |
pub use self::fs::File; |
pub use self::timer::Timer; |
pub use self::net::ip::IpAddr; |
pub use self::net::tcp::TcpListener; |
pub use self::net::tcp::TcpStream; |
pub use self::pipe::PipeStream; |
pub use self::process::{Process, Command}; |
Modules
extensions | Utility mixins that apply to all Readers and Writers |
fs | Synchronous File I/O |
net | Networking I/O |
pipe | Synchronous, in-memory pipes. |
process | Bindings for executing child processes |
stdio | Non-blocking access to stdin, stdout, and stderr. |
test | Various utility functions useful for writing I/O tests |
timer | Synchronous Timers |
util | Utility implementations of Reader and Writer |
Structs
BufReader | Reads from a fixed-size byte slice |
BufWriter | Writes to a fixed-size byte slice |
BufferedReader | Wraps a Reader and buffers input from it |
BufferedStream | Wraps a Stream and buffers input and output to and from it. |
BufferedWriter | Wraps a Writer and buffers output to it |
ChanReader | Allows reading from a rx. |
ChanWriter | Allows writing to a tx. |
Chars | An iterator that reads a utf8-encoded character on each iteration,
until |
FilePermission | /// A set of permissions for a file or directory is represented by a set of /// flags which are or'd together. |
FileStat | A structure used to describe metadata information about a file. This
structure is created through the |
IncomingConnections | An infinite iterator over incoming connection attempts.
Calling |
IoError | The type passed to I/O condition handlers to indicate error |
LineBufferedWriter | Wraps a Writer and buffers output to it, flushing whenever a newline ( |
Lines | An iterator that reads a line on each iteration,
until |
MemReader | Reads from an owned byte vector |
MemWriter | Writes to an owned, growable byte vector |
RefReader | A |
RefWriter | A |
TempDir | A wrapper for a path to temporary directory implementing automatic scope-based deletion. |
UnstableFileStat | This structure represents all of the possible information which can be
returned from a |
Enums
FileAccess | Access permissions with which the file should be opened. |
FileMode | A mode specifies how a file should be opened or created. These modes are
passed to |
FileType | Different kinds of files which can be identified by a call to stat |
IoErrorKind | A list specifying general categories of I/O error. |
SeekStyle | When seeking, the resulting cursor is offset from a base by the offset given
to the |
Constants
ALL_PERMISSIONS | /// All possible permissions enabled. |
GROUP_EXECUTE | |
GROUP_READ | |
GROUP_RWX | |
GROUP_WRITE | |
OTHER_EXECUTE | |
OTHER_READ | |
OTHER_RWX | |
OTHER_WRITE | |
USER_DIR | /// Permissions for user owned directories, equivalent to 0755 on /// unix-like systems. |
USER_EXEC | /// Permissions for user owned executables, equivalent to 0755 /// on unix-like systems. |
USER_EXECUTE | |
USER_FILE | /// Permissions for user owned files, equivalent to 0644 on unix-like /// systems. |
USER_READ | |
USER_RWX | |
USER_WRITE |
Traits
Acceptor | An acceptor is a value that presents incoming connections |
Buffer | A Buffer is a type of reader which has some form of internal buffering to
allow certain kinds of reading operations to be more optimized than others.
This type extends the |
BufferPrelude | Extension methods for the Buffer trait which are included in the prelude. |
ByRefReader | A reader which can be converted to a RefReader. |
ByRefWriter | A writer which can be converted to a RefWriter. |
BytesReader | A reader which can be converted to bytes. |
Listener | A listener is a value that can consume itself to start listening for connections. |
Reader | A trait for objects which are byte-oriented streams. Readers are defined by
one method, |
Seek | An object implementing |
Stream | A Stream is a readable and a writable object. Data written is typically received by the object which reads receive data from. |
Writer | A trait for objects which are byte-oriented streams. Writers are defined by
one method, |
Functions
standard_error | Creates a standard error for a commonly used flavor of error. The |
Type Definitions
IoResult | A convenient typedef of the return value of any I/O action. |