检查Python中打开的文件

Cla*_*diu 55 python debugging exception file

我在程序中遇到错误,该程序应该运行很长时间才能打开太多文件.有什么方法可以跟踪哪些文件是打开的,所以我可以偶尔打印出这个列表,看看问题出在哪里?

小智 42

要以跨平台方式列出所有打开的文件,我建议使用psutil.

#!/usr/bin/env python
import psutil

for proc in psutil.process_iter():
    print proc.open_files()
Run Code Online (Sandbox Code Playgroud)

原始问题隐含地将操作限制为当前正在运行的进程,可以通过psutil的Process类访问该进程.

proc = psutil.Process()
print proc.open_files()
Run Code Online (Sandbox Code Playgroud)

最后,您需要使用具有相应权限的帐户运行代码才能访问此信息,否则您可能会看到AccessDenied错误.

  • 这似乎只适用于基于磁盘的文件,而不适用于套接字,fifos等. (2认同)

Cla*_*diu 40

我最终将内置文件对象包装在程序的入口点.我发现我没有关闭我的记录器.

import io
import sys
import builtins
import traceback
from functools import wraps


def opener(old_open):
    @wraps(old_open)
    def tracking_open(*args, **kw):
        file = old_open(*args, **kw)

        old_close = file.close
        @wraps(old_close)
        def close():
            old_close()
            open_files.remove(file)
        file.close = close
        file.stack = traceback.extract_stack()

        open_files.add(file)
        return file
    return tracking_open


def print_open_files():
    print(f'### {len(open_files)} OPEN FILES: [{", ".join(f.name for f in open_files)}]', file=sys.stderr)
    for file in open_files:
        print(f'Open file {file.name}:\n{"".join(traceback.format_list(file.stack))}', file=sys.stderr)


open_files = set()
io.open = opener(io.open)
builtins.open = opener(builtins.open)
Run Code Online (Sandbox Code Playgroud)

  • 为了不延长文件对象的生命周期(因此防止在cpython中对引用计数对象进行自动关闭),IMO值得使用`weakref.WeakSet`而不是`open`为`openfiles`. (2认同)

Mik*_*one 23

在Linux上,您可以查看以下内容/proc/self/fd:

$ ls -l /proc/self/fd/
total 0
lrwx------ 1 foo users 64 Jan  7 15:15 0 -> /dev/pts/3
lrwx------ 1 foo users 64 Jan  7 15:15 1 -> /dev/pts/3
lrwx------ 1 foo users 64 Jan  7 15:15 2 -> /dev/pts/3
lr-x------ 1 foo users 64 Jan  7 15:15 3 -> /proc/9527/fd
Run Code Online (Sandbox Code Playgroud)

  • 这适用于提供`/ proc`文件系统的Linux系统.它独立于语言; 任何语言中任何可以访问`/ proc`中"文件"的程序都可以获得这些信息.我没有搞乱ipython,但基本的想法是在初始化后记录`/ proc/self/fd`的内容,然后在运行中稍后比较内容以查找更改. (2认同)

sha*_*unc 14

虽然上面打开的解决方案对于自己的代码很有用,但我正在调试我的客户端到第三方库,包括一些c扩展代码,所以我需要一个更直接的方法.以下例程在darwin下工作,并且(我希望)其他类似unix的环境:

def get_open_fds():
    '''
    return the number of open file descriptors for current process

    .. warning: will only work on UNIX-like os-es.
    '''
    import subprocess
    import os

    pid = os.getpid()
    procs = subprocess.check_output( 
        [ "lsof", '-w', '-Ff', "-p", str( pid ) ] )

    nprocs = len( 
        filter( 
            lambda s: s and s[ 0 ] == 'f' and s[1: ].isdigit(),
            procs.split( '\n' ) )
        )
    return nprocs
Run Code Online (Sandbox Code Playgroud)

如果有人可以扩展到可移植到Windows,我将不胜感激.


edu*_*ffy 9

在Linux上,您可以使用它lsof来显示进程打开的所有文件.

  • 有python一些lsof的内部函数,还是我真的要调用linux lsof? (2认同)

Rom*_*net 6

如前所述,您可以在 Linux 上的/proc/self/fd 中列出 fds ,这是一种以编程方式列出它们的简单方法:

import os
import sys
import errno

def list_fds():
    """List process currently open FDs and their target """
    if not sys.platform.startswith('linux'):
        raise NotImplementedError('Unsupported platform: %s' % sys.platform)

    ret = {}
    base = '/proc/self/fd'
    for num in os.listdir(base):
        path = None
        try:
            path = os.readlink(os.path.join(base, num))
        except OSError as err:
            # Last FD is always the "listdir" one (which may be closed)
            if err.errno != errno.ENOENT:
                raise
        ret[int(num)] = path

    return ret
Run Code Online (Sandbox Code Playgroud)


int*_*jay 5

在Windows上,您可以使用Process Explorer显示进程拥有的所有文件句柄.