programing

Python에서 열려있는 파일 확인

coolbiz 2021. 1. 17. 11:02
반응형

Python에서 열려있는 파일 확인


너무 많은 파일이 열려있는 오랫동안 실행되어야하는 프로그램에서 오류가 발생합니다. 어떤 파일이 열려 있는지 추적하여 가끔 해당 목록을 인쇄하고 문제가 어디에 있는지 확인할 수있는 방법이 있습니까?


모든 열린 파일을 플랫폼 간 방식으로 나열하려면 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 오류가 표시 될 수 있습니다.


내 프로그램의 진입 점에서 기본 제공 파일 개체를 래핑했습니다. 로거를 닫지 않는다는 것을 알았습니다.

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)

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

랩 열기 위의 솔루션은 자신의 코드에 유용하지만 일부 c 확장 코드를 포함하는 타사 라이브러리에 클라이언트를 디버깅하고 있었기 때문에보다 직접적인 방법이 필요했습니다. 다음 루틴은 다윈과 다른 유닉스 계열 환경에서 작동합니다.

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

누구든지 창문에 이식 할 수 있도록 확장 할 수 있다면 감사하겠습니다.


Linux에서는를 사용 lsof하여 프로세스에서 연 모든 파일을 표시 할 수 있습니다 .


Windows에서는 프로세스 탐색기사용하여 프로세스 가 소유 한 모든 파일 핸들을 표시 할 수 있습니다 .


수락 된 응답에는 파이프를 계산하지 않는 것처럼 보이는 몇 가지 제한 사항이 있습니다. 많은 하위 프로세스를 열고 통신에 사용되는 표준 입력, 출력 및 오류 파이프를 제대로 닫지 못하는 Python 스크립트가 있습니다. 수락 된 응답을 사용하면 이러한 열린 파이프를 열린 파일로 계산하지 못하지만 (적어도 Linux에서는) 열린 파일이며 열린 파일 제한에 포함됩니다. lsof -p솔루션은 sumid이 상황에서 shunc 작품 제안이 있기 때문에 또한 쇼 당신에게 열려있는 파이프.


앞서 말했듯이 / proc / self / fd 에서 Linux의 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

열려있는 모든 파일 목록을 가져옵니다. handle.exeMicrosoft의 Sysinternals Suite 의 일부입니다 . 대안은 psutil Python 모듈이지만 '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's 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)

나는 당신이 파일 설명자를 유출하고 있다고 생각합니다. 여는 모든 파일을 닫고 있는지 확인하기 위해 코드를 살펴보고 싶을 것입니다.


다음 스크립트를 사용할 수 있습니다. 그것은 Claudiu의 대답을 기반으로 합니다. 일부 문제를 해결하고 추가 기능을 추가합니다.

  • 파일이 열린 위치의 스택 추적을 인쇄합니다.
  • 프로그램 종료시 인쇄
  • 키워드 인수 지원

다음은 코드와 요점에 대한 링크 입니다.

"""
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/questions/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()

ReferenceURL : https://stackoverflow.com/questions/2023608/check-what-files-are-open-in-python

반응형