How to get info about files that are changing

I want to monitor a file that is being downloaded.
For example, print the size of the downloaded file every 5 milliseconds. The output is like below:

3kb downloaded..
8kb downloaded..
14kb downloaded..

Here's my wrong implementation:

use std::io;
use std::thread;
use std::fs::File;
use std::ops::DerefMut;
use std::time::Duration;
use std::sync::{Arc, Mutex};


fn main() {

    let pic = "https://www.rust-lang.org/logos/rust-logo-512x512.png";
    let mut resp = reqwest::blocking::get(pic).unwrap();
    let out = Arc::new(Mutex::new(File::create("Rust_Logo.png").unwrap()));
    let read_out = Arc::clone(&out);

    let pic_size = resp.content_length().unwrap();

    let download_process = thread::spawn(move || {

        let r_out = read_out.lock().unwrap();

        let mut downloaded = 0;

        while downloaded < pic_size {
            downloaded = r_out.metadata().unwrap().len();
            println!("{}kb downloaded..", downloaded / 1024);
            thread::sleep(Duration::from_millis(5));
            r_out.sync_all().unwrap();
        }

    });

    io::copy(&mut resp, out.lock().unwrap().deref_mut()).unwrap();
    download_process.join().unwrap();
}

The output is only one line, the size of the picture.
And I seem to know the reason: The lock is acquired first in the io::copy function, so acquiring the lock in the spawned thread will cause blocking. When the copy is over, the lock is released, so the blocking thread can continue. But this time the downloaded is already equal to pic_size, so we get one line output.

How can I implement a correct behavior as I mentioned before(While the size of file is growing up, the messages are printed.)? Thanks!

Write is implemented for &File, so you can simply avoid using a Mutex.

1 Like