move to fs::read_to_string

This is much more convenient!

Fixes #1355
This commit is contained in:
steveklabnik
2018-06-01 08:21:17 -04:00
parent fd146fc380
commit 5baf2e83e1
7 changed files with 68 additions and 69 deletions

View File

@@ -307,19 +307,22 @@ fn read_username_from_file() -> Result<String, io::Error> {
<span class="caption">Listing 9-6: A function that returns errors to the
calling code using `match`</span>
Lets look at the return type of the function first: `Result<String,
io::Error>`. This means the function is returning a value of the type
`Result<T, E>` where the generic parameter `T` has been filled in with the
concrete type `String`, and the generic type `E` has been filled in with the
concrete type `io::Error`. If this function succeeds without any problems, the
code that calls this function will receive an `Ok` value that holds a
`String`—the username that this function read from the file. If this function
encounters any problems, the code that calls this function will receive an
`Err` value that holds an instance of `io::Error` that contains more
information about what the problems were. We chose `io::Error` as the return
type of this function because that happens to be the type of the error value
returned from both of the operations were calling in this functions body that
might fail: the `File::open` function and the `read_to_string` method.
This function can be written in a much shorter way, but we're going to start by
doing a lot of it manually in order to explore error handling; at the end,
we'll show the easy way. Lets look at the return type of the function first:
`Result<String, io::Error>`. This means the function is returning a value of
the type `Result<T, E>` where the generic parameter `T` has been filled in
with the concrete type `String`, and the generic type `E` has been filled in
with the concrete type `io::Error`. If this function succeeds without any
problems, the code that calls this function will receive an `Ok` value that
holds a `String`—the username that this function read from the file. If this
function encounters any problems, the code that calls this function will
receive an `Err` value that holds an instance of `io::Error` that contains
more information about what the problems were. We chose `io::Error` as the
return type of this function because that happens to be the type of the error
value returned from both of the operations were calling in this functions
body that might fail: the `File::open` function and the `read_to_string`
method.
The body of the function starts by calling the `File::open` function. Then we
handle the `Result` value returned with a `match` similar to the `match` in
@@ -431,6 +434,30 @@ username in `s` when both `File::open` and `read_to_string` succeed rather than
returning errors. The functionality is again the same as in Listing 9-6 and
Listing 9-7; this is just a different, more ergonomic way to write it.
Speaking of different ways to write this function, there's a way to make this even
shorter:
<span class="filename">Filename: src/main.rs</span>
```rust
use std::io;
use std::io::Read;
use std::fs;
fn read_username_from_file() -> Result<String, io::Error> {
fs::read_to_string("hello.txt")
}
```
<span class="caption">Listing 9-9: Using `fs::read_to_string`</span>
Reading a file into a string is a fairly common operation, and so Rust
provides a convenience function called `fs::read_to_string` that will
open the file, create a new `String`, read the contents of the file,
and put the contents into that `String`, and then return it. Of course,
this doesn't give us the opportunity to show off all of this error handling,
so we did it the hard way at first.
#### The `?` Operator Can Only Be Used in Functions That Return `Result`
The `?` operator can only be used in functions that have a return type of

View File

@@ -192,7 +192,7 @@ impl Guess {
}
```
<span class="caption">Listing 9-9: A `Guess` type that will only continue with
<span class="caption">Listing 9-10: A `Guess` type that will only continue with
values between 1 and 100</span>
First, we define a struct named `Guess` that has a field named `value` that

View File

@@ -32,7 +32,7 @@ shown in Listing 12-4:
```rust,should_panic
use std::env;
use std::fs::File;
use std::fs;
use std::io::prelude::*;
fn main() {
@@ -45,11 +45,8 @@ fn main() {
// --snip--
println!("In file {}", filename);
let mut f = File::open(filename).expect("file not found");
let mut contents = String::new();
f.read_to_string(&mut contents)
.expect("something went wrong reading the file");
let contents = fs::read_to_string(filename)
.expect("Something went wrong reading the file");
println!("With text:\n{}", contents);
}
@@ -59,22 +56,18 @@ fn main() {
by the second argument</span>
First, we add some more `use` statements to bring in relevant parts of the
standard library: we need `std::fs::File` to handle files, and
standard library: we need `std::fs` to handle files, and
`std::io::prelude::*` contains various useful traits for doing I/O, including
file I/O. In the same way that Rust has a general prelude that brings certain
types and functions into scope automatically, the `std::io` module has its own
prelude of common types and functions youll need when working with I/O. Unlike
with the default prelude, we must explicitly add a `use` statement for the
prelude from `std::io`.
types and functions into scope automatically, the `std::io` module has its
own prelude of common types and functions youll need when working with I/O.
Unlike with the default prelude, we must explicitly add a `use` statement for
the prelude from `std::io`.
In `main`, weve added three statements: first, we get a mutable handle to the
file by calling the `File::open` function and passing it the value of the
`filename` variable. Second, we create a variable called `contents` and set it
to a mutable, empty `String`. This will hold the content of the file after we
read it in. Third, we call `read_to_string` on our file handle and pass a
mutable reference to `contents` as an argument.
In `main`, weve added a new statement: `fs::read_to_string` will take the
`filename`, open that file, and then produce a new `String` with its contents.
After those lines, weve again added a temporary `println!` statement that
After that lines, weve again added a temporary `println!` statement that
prints the value of `contents` after the file is read, so we can check that the
program is working so far.

View File

@@ -146,7 +146,8 @@ fn main() {
println!("Searching for {}", config.query);
println!("In file {}", config.filename);
let mut f = File::open(config.filename).expect("file not found");
let contents = fs::read_to_string(config.filename)
.expect("Something went wrong reading the file");
// --snip--
}
@@ -466,10 +467,7 @@ fn main() {
}
fn run(config: Config) {
let mut f = File::open(config.filename).expect("file not found");
let mut contents = String::new();
f.read_to_string(&mut contents)
let contents = fs::read_to_string(config.filename)
.expect("something went wrong reading the file");
println!("With text:\n{}", contents);
@@ -503,10 +501,7 @@ use std::error::Error;
// --snip--
fn run(config: Config) -> Result<(), Box<Error>> {
let mut f = File::open(config.filename)?;
let mut contents = String::new();
f.read_to_string(&mut contents)?;
let contents = fs::read_to_string(config.filename)?;
println!("With text:\n{}", contents);
@@ -530,7 +525,7 @@ have to specify what particular type the return value will be. This gives us
flexibility to return error values that may be of different types in different
error cases.
Second, weve removed the calls to `expect` in favor of `?`, as we talked about
Second, weve removed the call to `expect` in favor of `?`, as we talked about
in Chapter 9. Rather than `panic!` on an error, `?` will return the error value
from the current function for the caller to handle.

View File

@@ -279,8 +279,7 @@ will print each line returned from `search`:
pub fn run(config: Config) -> Result<(), Box<Error>> {
let mut f = File::open(config.filename)?;
let mut contents = String::new();
f.read_to_string(&mut contents)?;
let contents = fs::read_to_string(config.filename)?;
for line in search(&config.query, &contents) {
println!("{}", line);

View File

@@ -366,17 +366,14 @@ and send it.
```rust
# use std::io::prelude::*;
# use std::net::TcpStream;
use std::fs::File;
use std::fs;
// --snip--
fn handle_connection(mut stream: TcpStream) {
let mut buffer = [0; 512];
stream.read(&mut buffer).unwrap();
let mut file = File::open("hello.html").unwrap();
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
let contents = fs::read_to_string("hello.html").unwrap();
let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", contents);
@@ -421,7 +418,7 @@ received against what we know a request for */* looks like and adds `if` and
```rust
# use std::io::prelude::*;
# use std::net::TcpStream;
# use std::fs::File;
# use std::fs;
// --snip--
fn handle_connection(mut stream: TcpStream) {
@@ -431,10 +428,7 @@ fn handle_connection(mut stream: TcpStream) {
let get = b"GET / HTTP/1.1\r\n";
if buffer.starts_with(get) {
let mut file = File::open("hello.html").unwrap();
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
let contents = fs::read_to_string("hello.html").unwrap();
let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", contents);
@@ -476,17 +470,14 @@ indicating the response to the end user.
```rust
# use std::io::prelude::*;
# use std::net::TcpStream;
# use std::fs::File;
# use std::fs;
# fn handle_connection(mut stream: TcpStream) {
# if true {
// --snip--
} else {
let status_line = "HTTP/1.1 404 NOT FOUND\r\n\r\n";
let mut file = File::open("404.html").unwrap();
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
let contents = fs::read_to_string("404.html").unwrap();
let response = format!("{}{}", status_line, contents);
@@ -544,7 +535,7 @@ the large `if` and `else` blocks.
```rust
# use std::io::prelude::*;
# use std::net::TcpStream;
# use std::fs::File;
# use std::fs;
// --snip--
fn handle_connection(mut stream: TcpStream) {
@@ -560,10 +551,7 @@ fn handle_connection(mut stream: TcpStream) {
("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html")
};
let mut file = File::open(filename).unwrap();
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
let contents = fs::read_to_string(filename).unwrap();
let response = format!("{}{}", status_line, contents);

View File

@@ -389,7 +389,7 @@ use hello::ThreadPool;
use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
use std::fs::File;
use std::fs;
use std::thread;
use std::time::Duration;
@@ -424,10 +424,7 @@ fn handle_connection(mut stream: TcpStream) {
("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html")
};
let mut file = File::open(filename).unwrap();
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
let contents = fs::read_to_string(filename).unwrap();
let response = format!("{}{}", status_line, contents);