我的代码需要遍历目录中的文件,仅选择当前由系统上的任何其他进程打开(用于写入)的文件。
理想的解决方案适用于所有 Unix,但我会选择仅适用于 Linux。
该程序是用 Python 编写的,但如果必须的话,我可以添加自定义 C 函数——我只需要知道有哪些 API 可用于此...
我发现的一个建议是遍历 Linux 下的所有文件描述符/proc
,解析它们的链接以查看它们是否指向感兴趣的文件。不过好像比较重...
例如,我知道打开文件会增加其引用计数——文件系统不会释放已打开文件的块即使被删除- 直到关闭为止 - 所依赖的功能tmpfile(3)
。
也许,用户进程可以访问内核中的这些记录?
答案1
在 Linux 上,/proc/<pid>/fd/
包含由 . 保持打开的文件的符号链接列表<pid>
。这意味着您可以快速轻松地构建打开的文件列表此时此刻通过检查它们链接到的内容。
这并不像你想象的那么“重”。例如,在我古老的 AMD Phenom-II 1090T(当前正在运行大约 1000 个进程)上,甚至运行下面的 bash while/read 循环也只需要大约 1.5 秒。
在 bash 中,您可以使用以下内容构建关联数组:
declare -A openfiles
while IFS=$'\n' read l; do
openfiles[$l]=1
done < <(find /proc/*/fd/ -type l -printf '%l\0' |
grep -zvE '^(socket|pipe|anon_inode):' | sort -zu)
(这只是一个简单的例子,完全没有优化。优化起来一点也不难)
然后检查文件是否打开:
if [ "${openfiles[full-path-to-file]}" == 1 ] ; then .... ; fi
在 python 中,您可以使用os.walk()
和os.readlink()
构建一个字典。或者使用过程,进程文件系统或者普苏蒂尔模块。
psutil
是跨平台的,并且有一个open_files()
方法似乎在这里很有用。
注意:您可以使用 来执行此操作lsof
,但lsof
速度非常慢。它所做的远远超出了您这项工作所需的功能。
答案2
fnctl
就是您正在寻找的。它的man
页面非常详细。它告诉您打开的文件是只读还是可写,并为关闭的文件返回 -1。它功能强大,可以提供更多细节,例如(有缺陷的)锁定机制。
#include <fcntl.h>
int
fcntl(int fd, int cmd, ...);
为了您的目的,请使用该F_GETFL
标志,如下所示
int r, fd;
r = fcntl ( fd, F_GETFL );
if (r==-1)
printf("File %d is closed.\n", fd);
if (r>0)
printf("File %d is open.\n", fd);
如果返回值为 -1,则文件未打开(或者fd
不是有效的文件描述符)。如果返回值为正,fd
则描述一个打开的文件。