c++ - 尽管文件确实存在,std::filesystem::exists() 返回 false

标签 c++ g++ c++17

const std::string propName(pPropName, len);
std::filesystem::path p(pPropName);
if (!std::filesystem::exists(p)) {
    LOG(    Log::Level::ERROR,
            "File %s does not exist w/len = %u",
            propName.c_str(),
            len);
    return;
}

出于某种原因,std::filesystem::exists(p) 连续发生了几次返回 false (在我修改了现有文件并当文件确实存在时,使用 vi 保存 - 我立即对该文件进行 ls-ed。

a very similar postboost::filesystem::exists() 中报告了类似的问题。

其中的一个答案建议 vi 在保存文件之前创建一个临时文件(即 :w)。然而,上面的代码是在我在 vi 中点击 :wq! 几秒钟后手动触发的。我什至在1分钟和2分钟后又尝试了2次。 std::filesystem::exists() 仍然返回 false

另一个答案表明这可能是权限问题。然而,对我来说情况并非如此,因为 11 分钟后,相同的代码和相同的二进制文件看到了该文件(即 std::filesystem::exists() 返回 true)并且我什至没有重新启动我的进程(包含上面的代码)。

困难的部分是它不是 100% 可重现的——我刚刚编辑了上面的代码以传入 std::error_code 实例来尝试获取错误代码。但我现在无法重现它。

有什么想法吗?

我使用g++ 8.3.1编译,代码在CentOS 7.7上运行。

=====

更新 #1:文件大小约为 5190 字节,位于 3+GHz Intel 服务器上的 SSD 上。

更新 #2:这是 strace 的输出(当 std::filesystem::exists(p) 返回 true 时捕获):

stat("/server/my_file.ini", {st_mode=S_IFREG|0775, st_size=5077, ...}) = 0
open("/server/my_file.ini", O_RDONLY) = 15

更新 #3:发现问题 - pPropName 有时可能不会以 null 结尾(应该使用 propName)。并且 std::error_code.message().c_str() 返回“成功”,很奇怪。不管怎样,谢谢大家。

最佳答案

实际上是 vi 在创建新文件之前重命名了目标文件(这让我感到惊讶)。

我通过在编辑文件 (the_file) 时运行此程序来验证它。

#include <filesystem>
#include <iostream>
int main() {
    std::filesystem::path p("the_file");
    while(std::filesystem::exists(p));
    std::cout << "gone\n";
}

vi 中执行 :wq 时,程序会打印 gone 并退出。

此外,vi session 的 strace 也会对其进行验证。这是输入命令 :wq 后按回车键后的 strace -ff 日志。请注意renameopenat 序列:

read(0, "\r", 250)                      = 1
select(1, [0], [], [0], {tv_sec=0, tv_usec=0}) = 0 (Timeout)
write(1, "\r", 1)                       = 1
stat("/home/ted/proj/stackoverflow/the_file", {st_mode=S_IFREG|0644, st_size=7, ...}) = 0
access("/home/ted/proj/stackoverflow/the_file", W_OK) = 0
write(1, "\33[?25l\33[?2004l\33[>4;m", 20) = 20
ioctl(0, SNDCTL_TMR_START or TCSETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
write(1, "\"the_file\"", 10)            = 10
stat("the_file", {st_mode=S_IFREG|0644, st_size=7, ...}) = 0
access("the_file", W_OK)                = 0
getxattr("the_file", "system.posix_acl_access", 0x7fffb80a2f50, 132) = -1 ENODATA (No data available)
stat("the_file", {st_mode=S_IFREG|0644, st_size=7, ...}) = 0
lstat("the_file", {st_mode=S_IFREG|0644, st_size=7, ...}) = 0
lstat("4913", 0x7fffb80a32e0)           = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "4913", O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW, 0100644) = 3
fchown(3, 1000, 100)                    = 0
stat("4913", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
close(3)                                = 0
unlink("4913")                          = 0
stat("the_file~", 0x7fffb80a3000)       = -1 ENOENT (No such file or directory)
stat("the_file", {st_mode=S_IFREG|0644, st_size=7, ...}) = 0
stat("the_file~", 0x7fffb80a1fd0)       = -1 ENOENT (No such file or directory)
unlink("the_file~")                     = -1 ENOENT (No such file or directory)
rename("the_file", "the_file~")         = 0
openat(AT_FDCWD, "the_file", O_WRONLY|O_CREAT, 0644) = 3
ftruncate(3, 0)                         = 0
write(3, "hejsan\n", 7)                 = 7
fsync(3)                                = 0
stat("the_file", {st_mode=S_IFREG|0644, st_size=7, ...}) = 0
stat("the_file", {st_mode=S_IFREG|0644, st_size=7, ...}) = 0
fchmod(3, 0100644)                      = 0
close(3)                                = 0
setxattr("the_file", "system.posix_acl_access", "\2\0\0\0\1\0\6\0\377\377\377\377\4\0\4\0\377\377\377\377 \0\4\0\377\377\377\377", 28, 0) = 0
write(1, " 1L, 7C written", 15)         = 15
stat("/home/ted/proj/stackoverflow/the_file", {st_mode=S_IFREG|0644, st_size=7, ...}) = 0
unlink("the_file~")                     = 0
write(1, "\r\r\n\33[?2004l\33[?1l\33>", 18) = 18
write(1, "\33[?25h\33[>4;m\33[?1049l\33[23;0;0t", 29) = 29
close(4)                                = 0
unlink("/home/ted/proj/stackoverflow/.the_file.swp") = 0
exit_group(0)                           = ?
+++ exited with 0 +++

验证这一点的更简单方法是在使用 vi 之前和之后检查文件的 inode 编号。打开文件并执行 :wq 将创建一个新文件,并带有新的 inode 编号。

这并不能解释为什么文件在很长一段时间后不可见。这可能是因为某处有一些缓存。显然,XFS 文件系统存在(或曾经)存在一些问题,其缓存未针对小文件正确更新。也许你可以添加这个 if exists(p) == false:

system("sync;sync;sync"); // old classic tripple sync

将缓存写入同步到持久存储。之后,尝试再次检查。

关于c++ - 尽管文件确实存在,std::filesystem::exists() 返回 false,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62956322/

相关文章:

c++ - int的默认值是1吗?

c++ - 警告 : conversion to 'double' from 'long int' may alter its value

c++ - 为什么我在此函数中出现段错误?

c++ - 如何将范围放在枚举上?

c++ - 为什么在使用 DT_MODIFYSTRING 选项将拷贝传递给 DrawText 函数时原始 CString 会被覆盖?

c++ - 在 GCC 8 上工作的 Constexpr 计数器,并且不限于命名空间范围

c++ - 为什么 std::bind 不能与 std::filesystem::path 和 std::ostream 一起工作?

c++ - 静态存储中的内联变量什么时候初始化?

C++ 继承、模板和覆盖

c++ - CMake 无法检测 gcc 内置函数,如 sqrt、pow、exp 等