12.2.0 Before We Begin
In Chapter 12, we will build a real project: a command-line program. This program is a grep (Global Regular Expression Print), a tool for global regular-expression search and output. Its job is to search for the specified text in the specified file.
This project has several steps:
- Receive command-line arguments
- Read files (this article)
- Refactor: improve modules and error handling
- Use TDD (test-driven development) to develop library functionality
- Use environment variables
- Write error messages to standard error instead of standard output
If you find this helpful, please like, bookmark, and follow. To keep learning along, follow this series.
12.2.2 Review
Here is all the code written up to the previous article:
use std::env;
fn main() {
let args:Vec<String> = env::args().collect();
let query = &args[1];
let filename = &args[2];
println!("search for {}", query);
println!("In file {}", filename);
}
At this point, the code handles reading the userβs command-line input. Next we need to read the file based on that input.
12.2.3 Reading a File
To read a file, we need to import std::fs, which handles file-related operations:
use std::fs;
Next, read the file using filename:
let contents = fs::read_to_string(filename);
Reading can fail, so the return value is not the contents directly but a Result enum. For that enum, you can use expect to unwrap it. The argument to expect is the error message to print if something goes wrong (expect is covered in detail in 9.2. Result Enum and Recoverable Errors Pt. 1).
let contents = fs::read_to_string(filename)
.expect("Something went wrong while reading the file");// line break here is only to keep the line short
If the file is read successfully, print the contents:
println!("With text:\n{}", contents);
12.2.4 Testing the Code
At this point, we can test the code.
Here is all the code written so far:
use std::env;
use std::fs;
fn main() {
let args:Vec<String> = env::args().collect();
let query = &args[1];
let filename = &args[2];
println!("search for {}", query);
println!("In file {}", filename);
let contents = fs::read_to_string(filename)
.expect("Something went wrong while reading the file");// line break here is only to keep the line short
println!("With text:\n{}", contents);
}
First, create a .txt file in the project directory. You can name it whatever you like; I used poem.txt. Put some text in it, for example:
I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us - don't tell!
They'd banish us, you know.
How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!
Then run the command:
cargo run -- the poem.txt
- The
--separates Cargo command arguments from program arguments. It tells Cargo that what follows is not a Cargo option or argument, but an argument passed to the program. It is not read or stored. -
theis the text to search for and is stored inquery -
poem.txtis the file name and is stored infilename
Output:
$ cargo run -- the poem.txt
Compiling minigrep v0.1.0 (file:///projects/minigrep)
Finished `dev` profile [unoptimized +debuginfo] target(s) in 0.0s
Running `target/debug/minigrep the poem.txt`
Searching for the
In file poem.txt
With text:
I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us - don't tell!
They'd banish us, you know.
How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!
No problems.
Top comments (0)