我正在从这样的文件中读取行:
let file = File::open("/tmp/log.txt").unwrap();
let reader = BufReader::new(&file);
for line in reader.lines() {
// process lines
}
Run Code Online (Sandbox Code Playgroud)
从另一个进程我附加到文件
echo "hello" >> /tmp/log.txt
echo "world" >> /tmp/log.txt
...
Run Code Online (Sandbox Code Playgroud)
一段时间后,可以将更多消息附加到日志中。
目前我遇到一个问题,一旦读取了所有当前行,循环就会退出。我希望它等待(阻塞),直到更多行被推送到日志中。
我注意到,如果我 open stdin(),for循环将阻塞并等待标准输入输入更多行。
有没有办法实现相同的行为?
您可以使用notifycrate来监视文件更改。然后,如果您跟踪文件的大小,则可以在每次更改后使用该特征Seek,seek(SeekFrom::Start(last_file_end))并且仅读取新内容。
要重新创建tail -f /tmp/log.txt,您可以执行以下操作:
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
use std::fs::{self, File};
use std::io::{Read, Seek, SeekFrom};
use std::sync::mpsc;
use std::time::Duration;
fn main() {
let path = std::env::args().nth(1).unwrap();
let (tx, rx) = mpsc::channel();
let mut watcher = watcher(tx, Duration::from_millis(100)).unwrap();
watcher.watch(&path, RecursiveMode::NonRecursive).unwrap();
let mut contents = fs::read_to_string(&path).unwrap();
let mut pos = contents.len() as u64;
print!("{}", contents);
loop {
match rx.recv() {
Ok(DebouncedEvent::Write(_)) => {
let mut f = File::open(&path).unwrap();
f.seek(SeekFrom::Start(pos)).unwrap();
pos = f.metadata().unwrap().len();
contents.clear();
f.read_to_string(&mut contents).unwrap();
print!("{}", contents);
}
Ok(_) => {}
Err(err) => {
eprintln!("Error: {:?}", err);
std::process::exit(1);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
因此,通过 do 运行它cargo run -- /tmp/log.txt会复制 的行为tail -f /tmp/log.txt,其中它打印文件的内容,并随后在附加时输出其他内容。
请注意,它不处理截断或删除。在这种情况下,请检查DebouncedEvent枚举变体,并根据需要进行修改。此外,unwraps 可能应该处理得更好一些。
当然,lines()如果您愿意,您仍然可以使用:
let mut f = File::open(&path).unwrap();
f.seek(SeekFrom::Start(pos)).unwrap();
pos = f.metadata().unwrap().len();
let reader = BufReader::new(f);
for line in reader.lines() {
println!("> {:?}", line);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2181 次 |
| 最近记录: |