In Rust, input and output (I/O) operations are mainly handled through the std::io
module, which provides a number of important functionalities for performing I/O operations. Here’s a quick overview of some of the key features provided by std::io
.
Read and Write Traits
Two of the most important traits for I/O operations in Rust are Read
and Write
. These traits provide methods that allow bytes to be read from and written to streams respectively.
For example, any type that implements the Read
trait will provide a method read(&mut self, buf: &mut [u8]) -> Result
, which reads data into buf
and returns the number of bytes read. Similarity, any type that implements the Write
trait provides a method write(&mut self, buf: &[u8]) -> Result
, which writes the bytes from buf
and returns the number of bytes written.
Standard Input and Output
The std::io
module also provides functionality for interacting with the standard input (stdin
), standard output (stdout
), and standard error (stderr
) streams. For example:
use std::io::{self, Write};
fn main() -> io::Result<()> {
let mut input = String::new();
io::stdin().read_line(&mut input)?;
io::stdout().write_all(input.as_bytes())?;
Ok(())
}
In this example, read_line
is called on the standard input to read a line from the user, and then write_all
is called on the standard output to write this line out.
Files
The File
struct represents a file on the filesystem and it implements both the Read
and Write
traits, so you can perform I/O operations on files. Here’s an example:
use std::fs::File;
use std::io::prelude::*;
fn main() -> std::io::Result<()> {
let mut file = File::open("foo.txt")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let mut file = File::create("bar.txt")?;
file.write_all(contents.as_bytes())?;
Ok(())
}
In this example, the file foo.txt
is opened and read into a string. Then, a new file bar.txt
is created, and the contents of the string are written into it.
Buffered I/O
The std::io
module provides BufReader
and BufWriter
structs for buffered I/O operations. These wrap readers and writers and buffer their input and output, which can improve performance for certain types of I/O operations.
use std::io::BufReader;
use std::io::prelude::*;
use std::fs::File;
fn main() -> std::io::Result<()> {
let file = File::open("foo.txt")?;
let mut buf_reader = BufReader::new(file);
let mut contents = String::new();
buf_reader.read_to_string(&mut contents)?;
println!("{}", contents);
Ok(())
}
In this example, a BufReader
is created from a File
. This BufReader
can then be used to read from the file more efficiently.
Errors
Most operations in std::io
return the Result
type, which represents either a successful result (an Ok(T)
variant), or an error (an Err(E)
variant). This allows Rust to express I/O operations that could fail in a way that must be handled by your code. The ?
operator can be used to propagate these errors up the call stack.
A comprehensive case is as follows:
use std::io::Write;
fn main() {
/*
std::io::stdin() 返回标准输入流stdin的句柄。
read_line() stdin的句柄的一个方法,从标准输入流中读取一行数据
返回一个Result枚举。会自动删除行尾的换行符\n。
unwrap() 是一个帮助的方法,简化恢复错误的处理。返回Result中的存储实际值。
*/
let mut in_word = String::new();
let result = std::io::stdin().read_line(&mut in_word).unwrap();
println!("您输入的是:{}\n", in_word); // 您输入的是:hello
println!("读取的字节数为:{}\n", result); // 读取的字节数为:7
let result1 = std::io::stdout().write("Rust".as_bytes()).unwrap();
println!("写入的字节数为:{}\n", result1); // Rust写入的字节数为:4
let result2 = std::io::stdout().write("Hello".as_bytes()).unwrap();
println!("写入的字节数为:{}\n", result2); // Hello写入的字节数为:5
/*
std::io::stdout()返回标准输出流的句柄。
write()是标准输出流stdout的句柄上的一个方法,用于向标准输出流中写入字节流的内容。
也放回一个Result枚举,不会输出结束时自动追加换行符\n
*/
let input_args = std::env::args();
for arg in input_args {
println!("命令行参数:{}", arg);
}
/*
输出:
命令行参数:D:\Rust\io_23\target\debug\io_23.exe
命令行参数:Rust
命令行参数:Programming
命令行参数:Language
*/
}
In Rust, the unwrap()
method is a common way to handle error states represented by the Option
and Result
types.
Let’s break it down a bit:
Option
is a type in Rust that represents an optional value: every Option
is either Some(T)
(contains a value) or None
(does not contain a value).
Result
is a type in Rust that can represent either success (Ok(T)
) or failure (Err(E)
).
Both Option
and Result
types have the method unwrap()
. For an Option
, calling unwrap()
returns the contained value if it’s Some(T)
, but if it’s None
, it will cause the program to panic (crash).
For a Result
, calling unwrap()
returns the contained value if it’s Ok(T)
, but if it’s Err(E)
, it will also cause the program to panic.
So, the unwrap()
method is a somewhat risky operation to use, because while it’s a quick and easy way to obtain the inner value, it can cause your program to crash if the Option
is None
or the Result
is an Err
. In production code, it’s often preferable to handle errors more gracefully rather than using unwrap()
.