2

一般来说,一旦文件的句柄打开,文件就打开了,任何改变目录结构的人都无法改变它——文件可以移动、重命名或放置其他东西——它通过构造保持打开状态,如在 Linux/Unix 中,文件没有真正的删除,而只有unlink,这不一定会删除文件 - 它只是从目录中删除链接。结果:无论文件发生什么,文件句柄都将保持有效。

但是,如果底层设备消失(例如,文件位于从系统中删除的 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;(不清楚这是否会导致任何I/O)
4

2 回答 2

3

好吧,通常一个打开的文件会阻止卸载文件系统,所以它不应该在你下面消失。虽然使用 USB 磁盘等,但用户当然有可能在不询问系统的情况下拉动设备。

但是最好不要阻止干净卸载。这需要两件事:

  1. 不要保持文件打开
  2. 不要将包含目录保留为进程工作目录。

在路径上定期运行stat(2)将是执行此操作的方法。您可以检测对文件大小的修改mtimectime即文件大小的更改。inode 编号或包含设备 ( st_dev) 中的错误和更改可能表明该文件不再可访问或不再是同一个文件。根据应用要求做出反应。

(也就是说,假设您对当前由该名称指向的文件感兴趣,而不是对您打开的同一个inode感兴趣。)

至于 I/O,很可能定期stating 某些东西会将 inode 缓存在内存中,因此问题更多在于内存使用而不是 I/O。(直到您对文件执行足够的操作以致无法缓存它们,这会导致垃圾,内存和 I/O 的问题......)寻找到文件的末尾也同样需要加载该文件,我不明白为什么会导致任何重要的 I/O。

另一种选择是inotify(7)在文件或整个目录上使用以检测更改而不进行轮询。它还可以检测卸载事件。

于 2017-04-09T12:39:10.283 回答
2

成功打开文件后如何检测文件指针是否仍然有效

如果打开(或继承)它的进程FILE*没有明确地d并且如果有问题的进程没有调用未定义的行为,则根据定义是有效的。fclose()FILE*

如果任何底层都无法满足由FILE* fp's 进程发出的请求(通常通过调用 LIBC 或 或直接通过调用间接引发fread()fwrite()fseek()read(fileno(fp))失败的函数应返回指示错误条件并进行errno相应设置,这通常是EIO.

只需实施完整的错误检查和处理,您就不会遇到任何问题。

于 2017-04-09T14:20:22.963 回答