Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
223 views
in Technique[技术] by (71.8m points)

rust - Watch for file deletion and recreation

I have a BufReader on a File. I use read_line to read from the file. This is done at a fixed rate, say every five seconds. It is possible that in these five seconds the file is deleted and recreated with the same name. Unfortunately, the file and reader objects I have still retain references to the old unlinked file, and become a zombie.

MVCE:

use std::fs::File;
use std::io::{BufRead, BufReader};
use std::{thread, time};

fn main() -> std::io::Result<()> {
    let mut x = String::new();

    let f = File::open("foo.txt")?;
    let mut reader = BufReader::new(&f);
    let metadata = f.metadata()?;

    let res = reader.read_line(&mut x);
    println!("First: {:?}
{:?}
{:?}", metadata, x, res);

    let duration = time::Duration::from_millis(5000);
    thread::sleep(duration);
    // delete the file in this time

    let metadata = f.metadata()?;
    let res = reader.read_line(&mut x);
    println!("Second: {:?}
{:?}
{:?}", metadata, x, res);

    Ok(())
}

The output I get is:

First: Metadata { file_type: FileType(FileType { mode: 33204 }), is_dir: false, is_file: true, permissions: Permissions(FilePermissions { mode: 33204 }), modified: Ok(SystemTime { tv_sec: 1610027798, tv_nsec: 326270377 }), accessed: Ok(SystemTime { tv_sec: 1610027788, tv_nsec: 510393797 }), created: Ok(SystemTime { tv_sec: 1610027786, tv_nsec: 622417600 }) }
"1
"
Ok(2)
Second: Metadata { file_type: FileType(FileType { mode: 33204 }), is_dir: false, is_file: true, permissions: Permissions(FilePermissions { mode: 33204 }), modified: Ok(SystemTime { tv_sec: 1610027798, tv_nsec: 326270377 }), accessed: Ok(SystemTime { tv_sec: 1610027801, tv_nsec: 298233116 }), created: Ok(SystemTime { tv_sec: 1610027786, tv_nsec: 622417600 }) }
"1
"
Ok(0)

As you may see, both timestamps are identical, and there is no indication that the underlying File object has been unlinked from the main filesytem. The corresponding Python question uses os.fstat but I cannot figure out how to use the corresponding Rust alternative (which I think, is this).

My general algorithm every five seconds is:

  1. Use fstat to find number of active links of currently open File object.
  2. If the number of links is zero, reopen the File object.
  3. If the number of links is still zero, continue to step 1 after five seconds.
  4. Read_line from this file.

I'd appreciate help in figuring out how to do step 1, or if there's a different method to do this altogether.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The standard library does have methods for obtaining the number of links. They're just hidden behind OS specific extensions.

There's three MetadataExt traits, each in std::os::linux::fs, std::os::unix::fs, and std::os::windows::fs. Each with their own respective st_nlink(), nlinks(), and number_of_links(). Note the Windows' one is experimental.

Alternatively, you could also use e.g. the notify crate to watch for file events.


Unix:

use std::os::unix::fs::MetadataExt;

use std::fs::File;
use std::thread;
use std::time::Duration;

fn main() {
    let f = File::open("foo.txt").unwrap();

    println!("{:?}", f.metadata().unwrap().nlinks());
    // Prints `1`

    // Now delete `foo.txt`
    thread::sleep(Duration::from_secs(5));

    println!("{:?}", f.metadata().unwrap().nlinks());
    // Prints `0`
}

Windows:

#![feature(windows_by_handle)]

use std::os::windows::fs::MetadataExt;

use std::fs::File;
use std::thread;
use std::time::Duration;

fn main() {
    let f = File::open("foo.txt").unwrap();

    println!("{:?}", f.metadata().unwrap().number_of_links());
    // Prints `Some(1)`

    // Now delete `foo.txt`
    thread::sleep(Duration::from_secs(5));

    println!("{:?}", f.metadata().unwrap().number_of_links());
    // Prints `Some(0)`
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...