在 Linux 上,如果有一个长时间运行的进程每秒将时间戳写入文本文件,我如何自动从该文件读取时间戳?
这是我当前的实现:
fn read_timestamp() -> Result<String, &'static str> {
let path = "/timestamp.txt";
let metadata_result = fs::metadata(path);
match metadata_result {
Ok(_) => {
let lock_result = FileLock::lock(path, true, true);
match lock_result {
Ok(mut lock) => {
let mut content = String::new();
let read_result = lock.file.read_to_string(&mut content);
if read_result.is_ok() {
Ok(content)
} else {
Err("Cannot read file")
}
},
Err(_) => Err("Cannot acquire lock")
}
},
Err(_) => Err("File not found")
}
}
它看起来很笨重,我希望得到一些反馈。
最佳答案
我看到的一个大问题是锁定是活泼的,这实际上不会导致问题,但会导致不必要和无益的系统调用流量:从技术上讲,可以在对元数据
的调用之间删除文件> 和 FileLock::lock
。
所以我可能会直接执行 FileLock::lock
调用,然后检查其错误内容以进行错误报告,失败时返回 io::Error
所以应该告诉您,它具体出错是因为该文件不存在。
我觉得有点奇怪的另一件事是你对 match
的依赖,特别是考虑到你很少使用错误。
我倾向于使用更高级别的组合器,或用于一元或二进制代码路径的 if let
(特别是在忽略回退的有效负载时)。创建局部变量只是为了立即将其移动到匹配项也不是很习惯,您通常不会为局部变量操心。 YMMV 不过,它本身当然没有错误,它只是比我认为必要或合理的噪音更大。
这也可能受益于定制的错误类型,避免显式错误和匹配。无论如何,这是一个没有自定义错误类型的可能版本:
fn read_timestamp2() -> Result<String, &'static str> {
let path = "/timestamp.txt";
match FileLock::lock(path, true, true) {
Ok(mut lock) => {
let mut content = String::new();
lock.file.read_to_string(&mut content)
.map(|_| content)
.map_err(|_| "Cannot read file")
},
Err(e) if e.kind() == NotFound => Err("File not found"),
Err(_) => Err("Cannot acquire lock")
}
}
您可以进一步了解码合器:
fn read_timestamp() -> Result<String, &'static str> {
let path = "/timestamp.txt";
FileLock::lock(path, true, true)
.and_then(|mut lock| {
let mut content = String::new();
lock.file.read_to_string(&mut content)
.map(|_| content)
})
.map_err(|e| match e.kind() {
NotFound => Err("File not found"),
Interrupted | PermissionDenied | WouldBlock
=> Err("Cannot acquire lock"),
_ => Err("Cannot read file")
})
}
}
但请注意,此代码在其错误报告中并不真正正确:ErrorKind
相当不精确,所以实际上您需要调用 raw_os_error
并交叉引用手册页以了解哪些内容来自何处。
说实话,第二个版本有点古怪。
关于rust - 自动读取文件内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66594279/