Подтвердить что ты не робот

Проверить, какие файлы открыты в Python

Я получаю сообщение об ошибке в программе, которая должна работать в течение длительного времени, когда слишком много файлов открыты. Есть ли способ отслеживать, какие файлы открыты, поэтому я могу распечатать этот список изредка и посмотреть, где проблема?

4b9b3361

Ответ 1

Я закончил обертку встроенного файлового объекта в точке входа моей программы. Я узнал, что я не закрываю регистраторы.

import __builtin__
openfiles = set()
oldfile = __builtin__.file
class newfile(oldfile):
    def __init__(self, *args):
        self.x = args[0]
        print "### OPENING %s ###" % str(self.x)            
        oldfile.__init__(self, *args)
        openfiles.add(self)

    def close(self):
        print "### CLOSING %s ###" % str(self.x)
        oldfile.close(self)
        openfiles.remove(self)
oldopen = __builtin__.open
def newopen(*args):
    return newfile(*args)
__builtin__.file = newfile
__builtin__.open = newopen

def printOpenFiles():
    print "### %d OPEN FILES: [%s]" % (len(openfiles), ", ".join(f.x for f in openfiles))

Ответ 2

Чтобы перечислить все открытые файлы кросс-платформенным способом, я бы рекомендовал psutil.

#!/usr/bin/env python
import psutil

for proc in psutil.process_iter():
    print proc.open_files()

Исходный вопрос неявно ограничивает операцию текущим запуском процесса, к которому можно получить доступ через класс psutil Process.

proc = psutil.Process()
print proc.open_files()

Наконец, вы захотите запустить код с помощью учетной записи с соответствующими разрешениями для доступа к этой информации или вы можете увидеть ошибки AccessDenied.

Ответ 3

В 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

Ответ 4

Несмотря на то, что вышеприведенные решения, используемые для одного кода, полезны для одного собственного кода, я отлаживал мой клиент в сторонней библиотеке, включая некоторый код расширения 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

Если кто-то может продлить, чтобы быть портативным для окон, я был бы благодарен.

Ответ 5

В Linux вы можете использовать lsof, чтобы показать все файлы, открытые процессом.

Ответ 6

В Windows вы можете использовать Process Explorer, чтобы показать все файлы, принадлежащие процессу.

Ответ 7

Есть некоторые ограничения для принятого ответа, поскольку он не считает количество труб. У меня был python script, который открыл много подпроцессов и не смог правильно закрыть стандартные каналы ввода, вывода и ошибок, которые были использованы для связи. Если я использую принятый ответ, он не сможет считать эти открытые каналы открытыми, но (по крайней мере, в Linux) они являются открытыми файлами и считаются в пределе открытого файла. Решение lsof -p, предлагаемое sumid и shunc, работает в этой ситуации, поскольку оно также показывает вам открытые каналы.

Ответ 8

Как было сказано ранее, вы можете перечислить fds на Linux в /proc/self/fd, вот простой способ их программного программирования:

import os
import sys
import errno

def list_fds():
    """List process currently open FDs and their target """
    if sys.platform != 'linux2':
        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

Ответ 9

Я бы предположил, что вы пропускаете дескрипторы файлов. Вероятно, вы захотите просмотреть свой код, чтобы убедиться, что вы закрываете все файлы, которые вы открываете.

Ответ 10

Получить список всех открытых файлов. handle.exe является частью Microsoft Sysinternals Suite. Альтернативой является psutil Python module, но я нахожу, что "handle" будет печатать больше используемых файлов.

Вот что я сделал. Предупреждение кода Kludgy.

#!/bin/python3
# coding: utf-8
"""Build set of files that are in-use by processes.
   Requires 'handle.exe' from Microsoft SysInternals Suite.
   This seems to give a more complete list than using the psutil module.
"""

from collections import OrderedDict
import os
import re
import subprocess

# Path to handle executable
handle = "E:/Installers and ZIPs/Utility/Sysinternalssuite/handle.exe"

# Get output string from 'handle'
handle_str = subprocess.check_output([handle]).decode(encoding='ASCII')

""" Build list of lists.
    1. Split string output, using '-' * 78 as section breaks.
    2. Ignore first section, because it is executable version info.
    3. Turn list of strings into a list of lists, ignoring first item (it empty).
"""
work_list = [x.splitlines()[1:] for x in handle_str.split(sep='-' * 78)[1:]]

""" Build OrderedDict of pid information.
    pid_dict['pid_num'] = ['pid_name','open_file_1','open_file_2', ...]
"""
pid_dict = OrderedDict()
re1 = re.compile("(.*?\.exe) pid: ([0-9]+)")  # pid name, pid number
re2 = re.compile(".*File.*\s\s\s(.*)")  # File name
for x_list in work_list:
    key = ''
    file_values = []
    m1 = re1.match(x_list[0])
    if m1:
        key = m1.group(2)
#        file_values.append(m1.group(1))  # pid name first item in list

    for y_strings in x_list:
        m2 = re2.match(y_strings)
        if m2:
            file_values.append(m2.group(1))
    pid_dict[key] = file_values

# Make a set of all the open files
values = []
for v in pid_dict.values():
    values.extend(v)
files_open = sorted(set(values))

txt_file = os.path.join(os.getenv('TEMP'), 'lsof_handle_files')

with open(txt_file, 'w') as fd:
    for a in sorted(files_open):
        fd.write(a + '\n')
subprocess.call(['notepad', txt_file])
os.remove(txt_file)

Ответ 11

Вы можете использовать следующий script. Он основывается на ответе Клаудиу . Он решает некоторые проблемы и добавляет дополнительные функции:

  • Распечатывает трассировку стека, где был открыт файл.
  • Печать на выходе программы
  • Поддержка аргументов ключевых слов

Здесь код и ссылка на gist, возможно, более актуальную.

"""
Collect stacktraces of where files are opened, and prints them out before the
program exits.

Example
========

monitor.py
----------
from filemonitor import FileMonitor
FileMonitor().patch()
f = open('/bin/ls')
# end of monitor.py

$ python monitor.py
  ----------------------------------------------------------------------------
  path = /bin/ls
  >   File "monitor.py", line 3, in <module>
  >     f = open('/bin/ls')
  ----------------------------------------------------------------------------

Solution modified from:
https://stackoverflow.com/info/2023608/check-what-files-are-open-in-python
"""
from __future__ import print_function
import __builtin__
import traceback
import atexit
import textwrap


class FileMonitor(object):

    def __init__(self, print_only_open=True):
        self.openfiles = []
        self.oldfile = __builtin__.file
        self.oldopen = __builtin__.open

        self.do_print_only_open = print_only_open
        self.in_use = False

        class File(self.oldfile):

            def __init__(this, *args, **kwargs):
                path = args[0]

                self.oldfile.__init__(this, *args, **kwargs)
                if self.in_use:
                    return
                self.in_use = True
                self.openfiles.append((this, path, this._stack_trace()))
                self.in_use = False

            def close(this):
                self.oldfile.close(this)

            def _stack_trace(this):
                try:
                    raise RuntimeError()
                except RuntimeError as e:
                    stack = traceback.extract_stack()[:-2]
                    return traceback.format_list(stack)

        self.File = File

    def patch(self):
        __builtin__.file = self.File
        __builtin__.open = self.File

        atexit.register(self.exit_handler)

    def unpatch(self):
        __builtin__.file = self.oldfile
        __builtin__.open = self.oldopen

    def exit_handler(self):
        indent = '  > '
        terminal_width = 80
        for file, path, trace in self.openfiles:
            if file.closed and self.do_print_only_open:
                continue
            print("-" * terminal_width)
            print("  {} = {}".format('path', path))
            lines = ''.join(trace).splitlines()
            _updated_lines = []
            for l in lines:
                ul = textwrap.fill(l,
                                   initial_indent=indent,
                                   subsequent_indent=indent,
                                   width=terminal_width)
                _updated_lines.append(ul)
            lines = _updated_lines
            print('\n'.join(lines))
            print("-" * terminal_width)
            print()