6

Is there a simple way to get the number of files opened by a c++ program.

I would like to do it from my code, ideally in C++.

I found this blog article which is using a loop through all the available file descriptor and testing the result of fstat but I am wondering if there is any simpler way to do that.



Edit

It seems that there are no other solution than keeping a count of the files opened. Thanks to everybody for your help.

Kevin

Kevin MOLCARD
  • 2,168
  • 3
  • 22
  • 35

6 Answers6

2

Since the files are FILE *, we could do something like this:

In a headerfile that gets included everywhere:

#define fopen(x, y) debug_fopen(x, y, __FILE__, __LINE__)
#define fclose(x)   debug_fclose(x)

in "debugfile.cpp" (must obviously NOT use the above #define's)

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;
   }
}

(I haven't compiled this code, and it's meant to show the concept, it may have minor bugs, but I think the concept would hold - as long as your code, and not some third party library is leaking)

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
1

This is a legitimate question: I count open file descriptors in unit tests to verify none has leaked. On Linux systems there's one entry in /proc/self/fd for each open file descriptor, so you just have to count them. In c++17 it looks like this:

long file_descriptor_count() {
  return std::distance(std::filesystem::directory_iterator("/proc/self/fd"), std::filesystem::iterator{});
}
John Gordon
  • 2,576
  • 3
  • 24
  • 29
  • 1
    The advantage of this method is that it gets the OS count, including files opened through `std::fstream` and other methods. – MSalters Jan 23 '23 at 13:19
0

If you are under linux, this information is available under /proc/you_pid/fd.

Then use, lstat on each file descriptor to keep only regular files.

Matthieu Rouget
  • 3,289
  • 18
  • 23
0

there is a good practice that the scope of file opened in the smallest possible, open dump all information you want, or buffer into the fd, then close.

so this mean usual case we will have 3 fd the std in/out/err, plus all opened files.

keep track of your open files manually is the best, if you keep files opened.

put a global fdCounter variable, increment it after a successful file open, decremented after closing

aah134
  • 860
  • 12
  • 25
  • Thanks for the advice, however, reading the whole content of the files is definitely not possible in my application, in order to optimise RAM consumption. I have considered having a counter but I was looking for an easier way :). – Kevin MOLCARD Jun 13 '13 at 13:40
  • read as much as you like from the file then close, then open and seek to the last read position. or don't even close if you are just dealing with only one file until before app termination. how big is the application? – aah134 Jun 13 '13 at 13:46
  • This is a quiet complex application dealing with dozens of files. – Kevin MOLCARD Jun 13 '13 at 14:11
  • thats great, the bigger the app, its better having a class wrapper that can keep track of files, or at lease a class for each file, what contain current reading location, and file name. everytime you read or write you open file, access it, then close it before returning from the function call :) so file you are dealing with are closed all time until accessed via read/write – aah134 Jun 13 '13 at 14:14
0

If you encapsulated it properly, it should be simple to add reference counters or logging to it and print them to the console.

One approach to debug it is to override the open calls with your own implementation and from there call the real thing. Then you can also put some logging in, to see if you loose file descriptors. How do you open the files? With open() or are you using fopen()?

Something like this maybe:

#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;
}
Devolus
  • 21,661
  • 13
  • 66
  • 113
0

In my experience, by the time you need to count the number of file descriptors, you don't know where they were opened, by what submodule or library. Thus, wrapping open/close is not a viable strategy. Brute-force counting seems to be the only way.

The domain with the orig blog post no longer resolves in DNS. I copy two proposals from 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);

and also this:

#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;
}
Community
  • 1
  • 1
Linas
  • 773
  • 6
  • 13