在Windows上,如何打开以编写已经为另一个进程写入的文件?

时间:2013-08-13 13:07:19

标签: python windows logging file-io logrotate

我正在尝试打开另一个进程保持打开的日志文件并删除前几行。 在Unix上,我只需要os.open('/tmp/file.log', os.O_NONBLOCK),这会让我更接近目标。

现在我被Windows困住了,我需要以某种方式旋转这个日志,而不会结束持有该文件的应用程序。这甚至可能吗?

首先,我考虑在应用程序期望日志的位置打开文件句柄,并在Python中作为文件句柄的管道,但我无法在Windows上找到任何方法。

我还想过定期移动文件并让应用程序重新创建文件,但是因为正由另一个进程使用并没有太大帮助。

同样想到了O_SHLOCK,但又一次,那是Unix,而不是Windows。 所以我去了mmap这个文件,并希望它能让它变得更灵活,但这让我无处可去。

import mmap
import contextlib
import time

with open(r'test.log', 'r+') as f:
    with contextlib.closing(mmap.mmap(f.fileno(), 0)) as m:
        while 1:
            line = m.readline()
            if len(line) > 0:
                print line
            time.sleep(0.5)

这导致应用程序无法访问该文件,因为Python持有它(反之亦然)。

想到signal.SIGHUP,但在Windows中并不存在,所以回到原点。

我被困住了,我已经尝试过了,Python可以帮助我,还是我需要切换语言?

2 个答案:

答案 0 :(得分:3)

  

即使应用程序将文件作为共享对象打开,Python也不能   所以他们看起来不能相处。

这不是很糟糕:)。您可以(必须)使用CreateFile打开文件,如Augusto所指出的那样。您可以使用标准的 ctypes 模块。在问题Using a struct as a function argument with the python ctypes module中,您可以看到如何执行此操作。然后,您必须将C运行时文件描述符与您在上一步中获得的现有操作系统文件句柄相关联。您可以使用MS C运行时库(CRT)中的_open_osfhandle来执行此操作。您可以使用 ctypes 再次调用它;您可以ctypes.cdll.msvcrt._open_osfhandle访问它。然后,您必须将Python文件对象与您在上一步中获得的现有C运行时文件描述符相关联。要在Python 3中执行此操作,您只需将文件描述符作为内置open函数的第一个参数传递。根据文件

  

file 是一个字符串或字节对象,它将文件的路径名(绝对或相对于当前工作目录)提供给   打开或要包装的文件的整数文件描述符

在Python 2中,您必须使用os.fdopen;根据文档,它的任务是

  

返回连接到文件描述符fd

的打开文件对象

上述所有内容都不应该被要求做这么简单的事情。当CPython在Windows上的实现开始使用本机Windows API而不是通过C运行时库而不能访问Windows平台的许多功能时,希望它会简单得多。有关详细信息,请参阅Add new io.FileIO using the native Windows API问题。

答案 1 :(得分:2)

您是否可以控制生成日志文件的应用程序?因为取决于该应用程序打开文件的方式,您实际上无法对其进行修改。

此链接可能看起来偏离主题,但在Windows深处,确定对其他应用程序的文件访问权限的是dwShareMode函数的CreateFile参数:http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx

应用程序应该启用FILE_SHARE_WRITE并且可能启用FILE_SHARE_DELETE,并且应该在每次写入文件时刷新并更新文件位置。查看open()的Python documentation,没有这样详细的参数。