有没有一种简单的方法来获取c++程序打开的文件数。
我想从我的代码中做到这一点,最好是用 C++。
我发现这篇博客文章使用循环遍历所有可用的文件描述符并测试
fstat
的结果,但我想知道是否有更简单的方法可以做到这一点。
这是一个合理的问题:我在单元测试中计算打开的文件描述符以验证没有泄漏。在 Linux 系统上,每个打开的文件描述符在
/proc/self/fd
中都有一个条目,因此您只需对它们进行计数即可。在 c++17 中,它看起来像这样:
long file_descriptor_count() {
return std::distance(std::filesystem::directory_iterator("/proc/self/fd"), std::filesystem::iterator{});
}
由于文件是
FILE *
,我们可以这样做:
在到处都包含的头文件中:
#define fopen(x, y) debug_fopen(x, y, __FILE__, __LINE__)
#define fclose(x) debug_fclose(x)
在“debugfile.cpp”中(显然不能使用上面的
#define
)
struct FileInfo
{
FileInfo(const char *nm, const char fl, int ln) :
name(nm), file(fl), line(ln) {}
std::string name;
const char *file;
int line;
};
std::map<FILE*, FileInfo> filemap;
FILE *debug_fopen(const char *fname, const char *mode, const char *file, int line)
{
FILE *f = fopen(fname, mode);
if (f)
{
FileInfo inf(fname, file, line);
filemap[f] = inf;
}
}
int debug_fclose(FILE *f)
{
int res = fclose(f);
filemap.erase(f);
return res;
}
// Called at some points.
void debug_list_openfiles()
{
for( i : filemap )
{
cerr << "File" << (void *) i.first << " opened as " << i.second.name
<< " at " << i.second.file << ":" << i.second.line << endl;
}
}
(我还没有编译这段代码,它的目的是展示这个概念,它可能有小错误,但我认为这个概念会成立 - 只要你的代码,而不是某些第三方库泄漏)
如果您使用的是 Linux,可以在
/proc/you_pid/fd
下找到此信息。
然后在每个文件描述符上使用
lstat
仅保留常规文件。
如果正确封装它,向其添加引用计数器或日志记录并将其打印到控制台应该很简单。
调试它的一种方法是用您自己的实现覆盖开放调用,然后从那里调用真实的东西。然后您还可以进行一些日志记录,以查看是否丢失了文件描述符。你如何打开这些文件?使用
open()
还是您正在使用 fopen()
?
也许是这样的:
#include <fstream>
#include <iostream>
#include <stdlib.h>
#include <fcntl.h>
inline int log_open(char *p, int flags, int mode)
{
int fd = ::open(p, flags, mode);
std::cout << "OPEN: " << fd << std::endl;
return fd;
}
inline int log_close(int fd)
{
int rc = ::close(fd);
std::cout << "CLOSE: " << fd << std::endl;
return rc;
}
#define open(p, f, m) log_open(p, f, m)
#define close(fd) log_close(fd)
int main(int argc, char *argv[])
{
int fd = open("tmp.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);
std::cout << "FD: " << fd << std::endl;
if(fd != -1)
close(fd);
return 0;
}
根据我的经验,当您需要计算文件描述符的数量时,您不知道它们是在哪里打开的,由什么子模块或库打开。因此,环绕开/关并不是一个可行的策略。 暴力计数似乎是唯一的方法。
原始博客文章所在的域名不再在 DNS 中解析。我从 Find current number of open filehandle ( NOT lsof )
复制了两个建议int j, n = 0;
// count open file descriptors
for (j = 0; j < FDMAX; ++j) // FDMAX should be retrieved from process limits,
// but a constant value of >=4K should be
// adequate for most systems
{
int fd = dup (j);
if (fd < 0)
continue;
++n;
close (fd);
}
printf ("%d file descriptors open\n", n);
还有这个:
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main (void)
{
DIR *dp;
struct dirent *ep;
dp = opendir ("/proc/MYPID/fd/");
if (dp != NULL)
{
while (ep = readdir (dp))
puts (ep->d_name);
(void) closedir (dp);
}
else
perror ("Couldn't open the directory");
return 0;
}
有一个好的做法是打开的文件范围尽可能小,打开转储所有你想要的信息,或者缓冲到
fd
,然后关闭。
所以,这意味着通常情况下,我们将有 3 个
fd
,即 std
in
/out
/err
,以及所有打开的文件。
如果您保持文件打开状态,则最好手动跟踪打开的文件。
放置一个全局
fdCounter
变量,成功打开文件后递增,关闭后递减。