在文件打开时检查 C 中文件指针的有效性
Check the validity of a file pointer in C while the file is open
一般来说,一旦文件句柄打开,文件就打开了,任何人改变目录结构都无法改变 - 文件可以被移动、重命名或放置其他东西 - 它仍然存在通过构造打开,因为在 Linux/Unix 中没有真正的文件删除,只有 unlink
,这不一定删除文件 - 它只是从目录中删除 link。结果:无论文件发生什么,文件句柄都将保持有效。
但是,如果底层设备消失(例如,文件位于从系统中删除的 USB 记忆棒上),则将无法再访问该文件。
我有一个程序可以在启动时打开一些其他应用程序的巨大二进制文件 (> 4 GB)。之后,它通过查询
来监视文件的变化
long int pos = fseek(filepointer, 0L, SEEK_END);
经常(每隔几毫秒)并恢复到之前的位置,如果结果与 pos_before
不同。在这种情况下,fgets
用于从文件中读取新数据。
因此,只扫描文件尾部的变化,使整个过程相当轻量级。但是,它受到潜在问题的影响,如果更改文件系统(见上文),始终打开的文件指针可能会失效。
代码不需要移植到任何非Linux/Unix系统。
问题:
- 如何检测成功打开文件后文件指针是否仍然有效(这个事件可能是几周前发生的)?我已经看到有人可以使用
fcntl(fileno(filepointer), F_GETFD)
进行测试。
备选问题:
- 用其他方法检测文件大小的变化是否可行?我可以考虑定期使用
fseek(filepointer, 0L, SEEK_END);
(可能会很慢导致很多I/O),或者
_filelength(fileno(filepointer));
(不清楚这是否会导致很多I/O)
stat(filename, &st); st.st_size;
(不清楚这是否会导致 any I/O)
好吧,通常一个打开的文件会阻止卸载文件系统,所以它不应该就这么消失在你身下。尽管使用 USB 磁盘等,用户当然有可能在不询问系统的情况下拔出设备。
但是如果进程不 阻止完全卸载会更好。
这需要两件事:
- 不要让文件保持打开状态
- 不要将包含目录保留为进程工作目录。
运行 stat(2)
定期在路径上执行此操作。您可以检测文件的更改,从修改 mtime
、ctime
文件大小。 inode 编号或包含设备 (st_dev
) 中的错误和更改可能表明该文件不再可访问或不再是同一个文件。根据应用要求作出反应。
(也就是说,假设您对 name 当前指向的文件感兴趣,而不是同一个 inode你打开了。)
至于 I/O,很可能定期 stat
ing 某些东西会使索引节点缓存在内存中,因此问题更多的是内存使用而不是 I/O。 (直到你对文件执行此操作足以无法缓存它们,这会导致垃圾处理,内存和 I/O 的问题......)寻找文件的末尾同样需要加载文件的长度,我不明白为什么这会导致任何重要的 I/O.
另一种选择是对文件或整个目录使用 inotify(7)
来检测更改,而无需轮询。它还可以检测卸载事件。
How can I detect if the file pointer is still valid after having opened the file successfully
如果 FILE*
未被打开(或继承)它的进程显式 fclose()
d 并且 如果相关进程未调用Undefined Behaviour FILE*
根据定义有效。
以防任何底层无法满足 FILE* fp
进程发出的请求(通常通过调用 LIBC 间接提出,例如 fread()
、fwrite()
或 fseek()
,或者直接通过 read(fileno(fp))
) 失败的函数应该 return 指示错误条件并相应地设置 errno
,这通常是 EIO
.
只需实施完整的错误检查和处理,您就不会运行遇到任何问题。
一般来说,一旦文件句柄打开,文件就打开了,任何人改变目录结构都无法改变 - 文件可以被移动、重命名或放置其他东西 - 它仍然存在通过构造打开,因为在 Linux/Unix 中没有真正的文件删除,只有 unlink
,这不一定删除文件 - 它只是从目录中删除 link。结果:无论文件发生什么,文件句柄都将保持有效。
但是,如果底层设备消失(例如,文件位于从系统中删除的 USB 记忆棒上),则将无法再访问该文件。
我有一个程序可以在启动时打开一些其他应用程序的巨大二进制文件 (> 4 GB)。之后,它通过查询
来监视文件的变化long int pos = fseek(filepointer, 0L, SEEK_END);
经常(每隔几毫秒)并恢复到之前的位置,如果结果与 pos_before
不同。在这种情况下,fgets
用于从文件中读取新数据。
因此,只扫描文件尾部的变化,使整个过程相当轻量级。但是,它受到潜在问题的影响,如果更改文件系统(见上文),始终打开的文件指针可能会失效。
代码不需要移植到任何非Linux/Unix系统。
问题:
- 如何检测成功打开文件后文件指针是否仍然有效(这个事件可能是几周前发生的)?我已经看到有人可以使用
fcntl(fileno(filepointer), F_GETFD)
进行测试。
备选问题:
- 用其他方法检测文件大小的变化是否可行?我可以考虑定期使用
fseek(filepointer, 0L, SEEK_END);
(可能会很慢导致很多I/O),或者_filelength(fileno(filepointer));
(不清楚这是否会导致很多I/O)stat(filename, &st); st.st_size;
(不清楚这是否会导致 any I/O)
好吧,通常一个打开的文件会阻止卸载文件系统,所以它不应该就这么消失在你身下。尽管使用 USB 磁盘等,用户当然有可能在不询问系统的情况下拔出设备。
但是如果进程不 阻止完全卸载会更好。 这需要两件事:
- 不要让文件保持打开状态
- 不要将包含目录保留为进程工作目录。
运行 stat(2)
定期在路径上执行此操作。您可以检测文件的更改,从修改 mtime
、ctime
文件大小。 inode 编号或包含设备 (st_dev
) 中的错误和更改可能表明该文件不再可访问或不再是同一个文件。根据应用要求作出反应。
(也就是说,假设您对 name 当前指向的文件感兴趣,而不是同一个 inode你打开了。)
至于 I/O,很可能定期 stat
ing 某些东西会使索引节点缓存在内存中,因此问题更多的是内存使用而不是 I/O。 (直到你对文件执行此操作足以无法缓存它们,这会导致垃圾处理,内存和 I/O 的问题......)寻找文件的末尾同样需要加载文件的长度,我不明白为什么这会导致任何重要的 I/O.
另一种选择是对文件或整个目录使用 inotify(7)
来检测更改,而无需轮询。它还可以检测卸载事件。
How can I detect if the file pointer is still valid after having opened the file successfully
如果 FILE*
未被打开(或继承)它的进程显式 fclose()
d 并且 如果相关进程未调用Undefined Behaviour FILE*
根据定义有效。
以防任何底层无法满足 FILE* fp
进程发出的请求(通常通过调用 LIBC 间接提出,例如 fread()
、fwrite()
或 fseek()
,或者直接通过 read(fileno(fp))
) 失败的函数应该 return 指示错误条件并相应地设置 errno
,这通常是 EIO
.
只需实施完整的错误检查和处理,您就不会运行遇到任何问题。