Search code examples
fileasynchronousrustrust-tokio

How to copy file with tokio::fs


I am trying to copy a file using tokio for async operations. I saw that tokio doesn't expose any method like tokio::fs::copy which would do the job for me (like the equivalent std::fs::copy for sync operations).

While trying to implement such a method, i can't actually create a file using tokio::fs::File::create, that is the following code doesn't create any file:

tokio::fs::File::open("src.txt")
    .and_then(|mut file| {
        let mut content = Vec::new();
        file.read_buf(&mut content)
            .map(move |_| tokio::fs::File::create("dest.txt"))
    })
    .map_err(Error::from)
    .map(drop);

How can I copy src.txt into dest.txt using tokio and async fs methods?

Here is a link to Playground


Solution

  • Now tokio::fs has it's own copy implementation in version Tokio 0.2.11. (reference)

    //tokio = {version = "0.2.11", features = ["full"] }
    #[tokio::main]
    async fn main()-> Result<(), ::std::io::Error>{
        tokio::fs::copy("source.txt","target.txt").await?;
    
        Ok(())
    }
    

    Implementation is basically async-await version of the code below, please see the source code

    Without async await ( Tokio 0.1.x )

    You can use Copy future from tokio::io, which copies all bytes from input stream to output stream.

    //tokio-0.1.22
    tokio::fs::File::open("src.txt")
        .and_then(|mut file_in| {
            tokio::fs::File::create("dest.txt")
                .and_then(move |file_out| tokio::io::copy(file_in, file_out))
        })
        .map_err(Error::from)
        .map(drop);
    

    Playground


    Your code is not working because read_buf returns Poll not the Future so it won't combine with the inner one. It will do the same work for the small sized file if you spawn Future which is created by tokio::fs::File::create (full code).

    But be careful from the reference of read_buf :

    Pull some bytes from this source into the specified BufMut

    It doesn't read until the end of file with a single call. I don't know why this read example has no warning, it just says Read the contents of a file into a buffer, it looks like a misleading example.