## Reading a File

Now that we have some variables containing the information that we need, let's try using them. The next step is to open the file that we want to search. To do that, we need a file. Create one called `poem.txt` at the root level of your project, and fill it up with some Emily Dickinson:

Filename: poem.txt

    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!

With that in place, let's edit src/main.rs and add code to open the file as shown in Listing 12-3:

Filename: src/main.rs

    use std::env;
    use std::fs::File;
    use std::io::prelude::*;

    fn main() {
        let args: Vec<String> = env::args().collect();

        let search = &args[1];
        let filename = &args[2];

        println!("Searching for {}", search);
        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");

        println!("With text:\n{}", contents);
    }

Listing 12-3: Read the contents of the file specified by the second argument

We've added a few things. First of all, we need some more `use` statements to bring in the relevant parts of the standard library: we need `std::fs::File` for dealing with files, and `std::io::prelude::*` contains various traits that are useful when doing I/O, including file I/O. In the same way that Rust has a general prelude that brings certain things into scope automatically, the `std::io` module has its own prelude of common things you'll need when working with I/O. Unlike the default prelude, we must explicitly `use` the prelude in `std::io`.

In `main`, we've added three things: first, we get a handle to the file and open it by using the `File::open` function and passing it the name of the file specified in the second argument. Second, we create a mutable, empty `String` in the variable `contents`, then call `read_to_string` on our file handle with our `contents` string as the argument; `contents` is where `read_to_string` will place the data it reads. Finally, we print out the entire file contents, which is a way for us to be sure our program is working so far.

Let's try running this code, specifying any string for the first argument (since we haven't implemented the searching part yet) and our poem.txt file as the second argument:

    $ cargo run the poem.txt
        Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
         Running `target\debug\greprs.exe 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!

Great! Our code is working. However, it's got a few flaws. Because our program is still small, these flaws aren't a huge deal, but as our program grows, it will be harder and harder to fix them in a clean way. Let's do the refactoring now, instead of waiting. The refactoring will be much easier to do with only this small amount of code.