如何找出哪个代码行打开文件?

时间:2013-05-10 17:34:25

标签: python django

我最近在我的服务器上遇到一个关于“打开太多文件”的异常。我查了一下lsof,果然,还有一堆PDF文件保持打开状态(全部在同一目录下)。此特定文件通过Django FileField进行管理。我试图追踪我的项目中明确按名称打开文件的任何地方,并且我只能找到一个地方,并且我可以告诉文件正确地在那里关闭。可能还有其他地方文件仍处于打开状态,但我不知道如何找出实际保持文件打开的代码段。我试过简单地调用open()和file(),但没有运气。

有没有办法系统地跟踪哪些代码行负责让文件保持打开状态?

编辑:我了解如何正确打开/关闭文件。我的问题是,是否有办法跟踪现有的代码行,即保留文件。

2 个答案:

答案 0 :(得分:4)

使用open时,请尝试将其用作上下文管理器。这样,无论发生什么事情,当你完成它时它会被关闭:

with open('file.txt', 'r') as fin:
    # Access fin like normal

# No matter what happens, after the block, it's closed!

或者,您可以使用自己的函数替换openclose的实例,为您执行额外的日志记录:

def my_open(filename, *args):
    logger.debug('Opening %s' % filename)
    return open(filename, *args)

def my_close(file_obj):
    logger.debug('Closing %s' % file_obj.name)
    return file_obj.close()

作为最后的手段,如果您无法访问相关代码,或者更改它会很繁琐,您可以尝试使用猴子修补函数。

import traceback
class MyFile(file):
    @staticmethod
    def open(*args, **kwargs):
        return MyFile(*args, **kwargs)

    def __init__(self, *args, **kwargs):
        self._file = self._open(*args, **kwargs)
        print('Opening %s from %s' % (
            self._file.name, ''.join(traceback.format_stack())))

    def close(self):
        print('Closing file %s from %s' % (
            self._file.name, ''.join(traceback.format_stack())))
        self._file.close()

# Now the monkey-patching
file = MyFile
MyFile._open = open
open = MyFile.open

o = open('hello', 'w+')

它当然不是世界上最漂亮的东西,但如果你能够修补它,那么你至少可以处理遗留代码。

答案 1 :(得分:0)

您是否依赖垃圾收集器来关闭文件? I.E.句柄超出范围,即使你“关闭”了文件,它也不会消失,直到GC运行。如果对象链永远不会超出范围,GC无法收集它。此外,如果GC没有机会运行,也不会收集它们。

我遇到了一个长时间运行过程的相同问题,并通过重新设计我的系统来“解决”它,以便所有文件访问都发生在子对象内部。在完成使用后,该对象已从参考链中删除,或发生了一些错误。这允许GC收集句柄。