1
1
# ` read_lines `
2
2
3
- ## Beginner friendly method
4
- This method is NOT efficient. It's here for beginners
5
- who can't understand the efficient method yet.
3
+ ## A naive approach
6
4
7
- ``` rust,no_run
8
- use std::fs::File;
9
- use std::io::{ self, BufRead, BufReader };
5
+ This might be a reasonable first attempt for a beginner's first
6
+ implementation for reading lines from a file.
10
7
11
- fn read_lines(filename: String) -> io::Lines<BufReader<File>> {
12
- // Open the file in read-only mode.
13
- let file = File::open(filename).unwrap();
14
- // Read the file line by line, and return an iterator of the lines of the file.
15
- return io::BufReader::new(file).lines();
16
- }
8
+ ``` rust,norun
9
+ use std::fs::read_to_string;
17
10
18
- fn main() {
19
- // Stores the iterator of lines of the file in lines variable.
20
- let lines = read_lines("./hosts".to_string());
21
- // Iterate over the lines of the file, and in this case print them.
22
- for line in lines {
23
- println!("{}", line.unwrap());
11
+ fn read_lines(filename: &str) -> Vec<String> {
12
+ let mut result = Vec::new();
13
+
14
+ for line in read_to_string(filename).unwrap().lines() {
15
+ result.push(line.to_string())
24
16
}
17
+
18
+ result
25
19
}
26
20
```
27
21
28
- Running this program simply prints the lines individually.
29
- ``` shell
30
- $ echo -e " 127.0.0.1\n192.168.0.1\n" > hosts
31
- $ rustc read_lines.rs && ./read_lines
32
- 127.0.0.1
33
- 192.168.0.1
22
+ Since the method ` lines() ` returns an iterator over the lines in the file,
23
+ we can also perform a map inline and collect the results, yielding a more
24
+ concise and fluent expression.
25
+
26
+ ``` rust,norun
27
+ use std::fs::read_to_string;
28
+
29
+ fn read_lines(filename: &str) -> Vec<String> {
30
+ read_to_string(filename)
31
+ .unwrap() // panic on possible file-reading errors
32
+ .lines() // split the string into an iterator of string slices
33
+ .map(String::from) // make each slice into a string
34
+ .collect() // gather them together into a vector
35
+ }
34
36
```
35
37
36
- ## Efficient method
37
- The method ` lines() ` returns an iterator over the lines
38
- of a file .
38
+ Note that in both examples above, we must convert the ` &str ` reference
39
+ returned from ` lines() ` to the owned type ` String ` , using ` .to_string() `
40
+ and ` String::from ` respectively .
39
41
40
- ` File::open ` expects a generic, ` AsRef<Path> ` . That's what
41
- ` read_lines() ` expects as input.
42
+ ## A more efficient approach
43
+
44
+ Here we pass ownership of the open ` File ` to a ` BufReader ` struct. ` BufReader ` uses an internal
45
+ buffer to reduce intermediate allocations.
46
+
47
+ We also update ` read_lines ` to return an iterator instead of allocating new
48
+ ` String ` objects in memory for each line.
42
49
43
50
``` rust,no_run
44
51
use std::fs::File;
45
52
use std::io::{self, BufRead};
46
53
use std::path::Path;
47
54
48
55
fn main() {
49
- // File hosts must exist in current path before this produces output
50
- if let Ok(lines) = read_lines("./hosts") {
56
+ // File hosts.txt must exist in the current path
57
+ if let Ok(lines) = read_lines("./hosts.txt ") {
51
58
// Consumes the iterator, returns an (Optional) String
52
59
for line in lines {
53
60
if let Ok(ip) = line {
@@ -68,11 +75,15 @@ where P: AsRef<Path>, {
68
75
69
76
Running this program simply prints the lines individually.
70
77
``` shell
71
- $ echo -e " 127.0.0.1\n192.168.0.1\n" > hosts
78
+ $ echo -e " 127.0.0.1\n192.168.0.1\n" > hosts.txt
72
79
$ rustc read_lines.rs && ./read_lines
73
80
127.0.0.1
74
81
192.168.0.1
75
82
```
76
83
77
- This process is more efficient than creating a ` String ` in memory
78
- especially working with larger files.
84
+ (Note that since ` File::open ` expects a generic ` AsRef<Path> ` as argument, we define our
85
+ generic ` read_lines() ` method with the same generic constraint, using the ` where ` keyword.)
86
+
87
+ This process is more efficient than creating a ` String ` in memory with all of the file's
88
+ contents. This can especially cause performance issues when working with larger files.
89
+
0 commit comments