8

Let's say I have a list of the opened files (actually, of the file numbers):

import resource
import fcntl

def get_open_fds():
    fds = []
    soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
    for fd in range(3, soft):
        try:
            flags = fcntl.fcntl(fd, fcntl.F_GETFD)
        except IOError:
            continue
        fds.append(fd)
    return fds

Now I would like to get the names of those files. How can I do this?

EDIT

Just to clarify, for those downvoting this: fd is an integer. It is NOT a filedescriptor. Sorry for confusing you with the name, but the code is self-explanatory.

EDIT2

I am getting flamed about this, I think because of my choice of fd to mean file number. I just checked the documentation:

All functions in this module take a file descriptor fd as their first argument. This can be an integer file descriptor, such as returned by sys.stdin.fileno(), or a file object, such as sys.stdin itself, which provides a fileno() which returns a genuine file descriptor.

So fd is indeed an integer. It can also be a file object but, in the general case, fd has not .name.

blueFast
  • 41,341
  • 63
  • 198
  • 344
  • What's the reason behind using file numbers? If someone adds or removes a file, all the numbers point to a wrong file. –  Nov 29 '12 at 10:36
  • 1
    Sorry, but you are not answering my question. You may be right that this in not the right approach, but I am not asking about this. I am specifically asking: "Get file object from file number". Is this possible? If it is: how? – blueFast Nov 29 '12 at 10:39
  • You are right. I have a (long, complicated) codebase, which is leaking file descriptors. I do not known which component is responsible. I want to know, at a specific moment, which files are still open, so that I know where to start fixing my problems. I have been able to list the *file numbers* with the function that I just posted. Now I would like to know the names of those files. @thg435 has posted a valid answer, but maybe there is a better approach to my problem. Maybe there is a better way of listing all opened file objects directly? – blueFast Nov 29 '12 at 10:57
  • @user1632861: Why don't you just answer his question, and then add any warnings you feel appropriate? Others will see both question and answer, and those that actually need the solution to the question as asked will benefit. This is StackOverflow: many eyes beyond the poster's will see the info, and benefit. Don't hoard your knowledge. – Ethan Furman Apr 16 '14 at 19:32
  • In Python3 os.fdopen() could be used. – rysson Mar 14 '23 at 15:03

2 Answers2

6

As per this answer:

for fd in get_open_fds():
    print fd, os.readlink('/proc/self/fd/%d' % fd)
Community
  • 1
  • 1
georg
  • 211,518
  • 52
  • 313
  • 390
  • Thanks. This is very linux specific, but it is good enough for me. – blueFast Nov 29 '12 at 10:52
  • 2
    Actually, this is giving me the file name. What I need is actually the file object, so that I can access all properties of the file. Is this possible? – blueFast Nov 29 '12 at 11:27
2

I was in the same boat. What I ended up doing is writing my own open that keeps track of all the files opened. Then in the initial Python file the first thing that happens is the built-in open gets replaced by mine, and then later I can query it for the currently open files. This is what it looks like:

class Open(object):
    builtin_open = open
    _cache = {}
    @classmethod
    def __call__(cls, name, *args):
        file = cls.builtin_open(name, *args)
        cls._cache[name] = file
        return file
    @classmethod
    def active(cls, name):
        cls.open_files()
        try:
            return cls._cache[name]
        except KeyError:
            raise ValueError('%s has been closed' % name)
    @classmethod
    def open_files(cls):
        closed = []
        for name, file in cls._cache.items():
            if file.closed:
                closed.append(name)
        for name in closed:
            cls._cache.pop(name)
        return cls._cache.items()

import __builtin__
__builtin__.open = Open()

then later...

daemon.files_preserve = [open.active('/dev/urandom')]
Ethan Furman
  • 63,992
  • 20
  • 159
  • 237