Basic tokio file read issue

I tried to follow the example at: https://docs.rs/tokio/0.1.22/tokio/fs/struct.File.html

in my Cargo.toml I have:

[dependencies]
tokio = { version = "0.2.11", features = ["full"] }
serde_json = "1.0.48"

But the code is complaining it cannot find the Futures trait, instead It is trying to find:

error[E0599]: no method named `and_then` found for type `impl std::future::Future` in the current scope
 --> src\main.rs:8:10
  |
8 |         .and_then(|mut file| {
  |          ^^^^^^^^ method not found in `impl std::future::Future`

The code is an exact clone of the example in the tokio docs:

extern crate tokio;

use tokio::prelude::{AsyncRead, Future};

fn reader() {

    let task = tokio::fs::File::open("foo.txt")

        .and_then(|mut file| {

            let mut contents = vec![];

            file.read_buf(&mut contents)

                .map(|res| {

                    println!("{:?}", res);

                })

        }).map_err(|err| eprintln!("IO error: {:?}", err));

    tokio::run(task);

}

This is an example from an old version of Tokio. The modern version looks like this:

use tokio::fs::File;
use tokio::io::{AsyncReadExt, Error};

async fn reader() -> Result<(), Error> {
    let mut file = File::open("foo.txt").await?;
    let mut contents = vec![];
    file.read_to_end(&mut contents).await?;
    println!("{:?}", contents);
    Ok(())
}

#[tokio::main]
async fn main() {
    reader().await.unwrap();
}

You are looking for version 0.2.x.

1 Like

I found I had to do something a bit fancier for the Error return. Why?

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

mod parser;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let args: Vec<String> = env::args().collect();
    println!("arguments: {:?}", args);
    let file_name = String::from(&args[1]);
    let file = open_file(file_name).await?;
    let contents = read_file(file).await?;
    println!("len = {}", contents.len());
    println!("{}", contents);
    let _ = parser::parser(contents);
    return Ok(());
}

async fn open_file(file_name: String) -> Result<File, Box<dyn std::error::Error>> {
    let file = File::open(file_name).await?;
    return Ok(file);
}

async fn read_file(mut file: File) -> Result<String, Box<dyn std::error::Error>> {
    let mut contents = vec![];
    file.read_to_end(&mut contents).await?;
    let json_string = String::from_utf8(contents)?;
    return Ok(json_string);
}

I simply used the io error type, but if one of the function calls can fail with something that isn't an io error, naturally you will need a different error type.

Be aware that the return on the last line of a function is usually left out, like I did in my example.