2013-08-03 14 views
0

我有一个文件列表,并且在一次使用中只有一个。所以我想知道哪个文件正在被特定的程序使用。因为我可以使用'unlocker'来找出正在使用的文件,就像这样提到的question。但我想要一种编程方式,以便我的程序可以帮助我找出答案。有什么办法吗?在Python中我怎么知道给定的文件正在使用

特别是,在任何r/w模式下,访问使用文件和python的简单的'open'函数都不会抛出任何异常。我可以告诉哪个文件只能被'unlocker'使用。

我发现在w模式下的python'open'函数已经从该特定程序获得了访问权限,然后该程序不能很好地工作。在这一刻我打开解锁器,我可以看到两个进程访问该文件。是否有任何'弱'的方法,只能检测文件是否被使用?

+0

是否有打开文件的.filename.swp文件? – Matt

+0

@Matt:不,没有。 – abarnert

+0

@Matt:只有VIM才能打开文件。 – nneonneo

回答

0

您可以使用try/except块。

check if a file is open in Python

try: 
    f = open("file.txt", "r") 
    except IOError: 
    print "This file is already in use" 
+0

对不起,我的问题刚刚不太清楚。正在使用的文件可以在两种r/w模式下“打开”。这就是困惑我的地方。有没有其他方法? – prehawk

3

我不知道你想找到这两个的:

  • 是否有任何现有的把手给定文件,如handleProcess Explorer工具节目?
  • 是否存在锁定对于给定文件的处理,如Unlocker工具显示。

但无论哪种方式,答案都是类似的。

显然这是可行的,或者那些工具不能这样做,对吧?不幸的是,Python stdlib中没有任何东西可以提供帮助。你是怎么做到的?

您将需要访问Windows API功能 - 通过pywin32,​​或其他。

有两种方法可以解决这个问题。第一种方法是使用NT内核对象API,这非常困难,而且只有在需要使用非常旧版本的Windows时才真正需要。第二个,NtQuerySystemInformation,是你可能想要的。

细节非常复杂(并没有很好的记录),但他们解释in a CodeProject sample programon the Sysinternals forums

如果你不理解这些页面上的代码,或者如何从Python调用它,那么你真的不应该这样做。如果你了解要点,但有疑问或陷入困境,当然你可以在这里寻求帮助(或者在sysinternals论坛或其他地方)。

但是,即使你已经使用​​for Windows之前,还有你可能不知道几点需要注意一下:

许多功能要么不记录,或文档没有告诉你哪些DLL找到他们。他们都将在ntdllkernel32;但在某些情况下,NtFooBar文档名称只是真实ZwFooBar函数的别名,因此如果在任一DLL中找不到NtFooBar,请查找ZwFooBar

至少在旧版本的Windows,ZwQuerySystemInformation不作为你所期望的:你不能用一个0 SystemInformationLength调用它,检查ReturnLength,分配该大小的缓冲区,然后再试一次。你可以做的唯一的事情是从一个有足够空间的缓冲区开始,例如8个句柄,尝试一下,看看你是否得到一个错误STATUS_INFO_LENGTH_MISMATCH,增加这个数字8,然后再试一次,直到它成功(或者失败并产生一个不同的错误)。该代码看起来是这样的(假设你已经定义了SYSTEM_HANDLE结构):

STATUS_INFO_LENGTH_MISMATCH = 0xc0000004 
i = 8 
while True: 
    class SYSTEM_HANDLE_INFORMATION(Structure): 
     _fields_ = [('HandleCount', c_ulong), 
        ('Handles', SYSTEM_HANDLE * i)] 
    buf = SYSTEM_HANDLE_INFORMATION() 
    return_length = sizeof(buf) 
    rc = ntdll.ZwQuerySystemInformation(SystemHandleInformation, 
             buf, sizeof(buf), 
             byref(return_length)) 
    if rc == STATUS_INFO_LENGTH_MISMATCH: 
     i += 8 
     continue 
    elif rc == 0: 
     return buf.Handles[:buf.HandleCount] 
    else: 
     raise SomeKindOfError(rc) 

最后,该文件并没有真正解释任何地方,但你知道一个HANDLE获得的方式是一个文件到一个路径名是有点复杂。只需使用NtQueryObject(ObjectNameInformation)就会返回内核对象空间路径名,然后您必须将其映射到DOS路径名,可能为UNC的普通NT路径名或\?\路径名。当然,第一个不能在没有映射盘符的网络驱动器上工作;前两种都不适用于路径很长的文件。


当然还有一个更简单的选择:只要开handleUnlocker,或通过subprocess其他一些命令行工具。


或者介于两者之间,建立上面链接CodeProject上的项目,只是通过​​打开它的DLL并调用其GetOpenedFiles方法,它会做的辛勤工作为您服务。

由于该项目构建了一个正常的WinDLL样式的DLL,因此可以使用正常的​​方式调用它。如果您从未使用​​,文档中的示例显示您几乎需要知道的所有内容,但我会给出一些伪代码来帮助您开始。

首先,我们需要为您要编写的回调函数创建一个OF_CALLBACK类型,如Callback functions中所述。由于OF_CALLBACK的原型是在.h文件中定义的,我无法到达这里,我只是在猜测它。你必须看看真实的版本并自己翻译。但是,你的代码将是这个样子:

from ctypes import windll, c_int, WINFUNCTYPE 
from ctypes.wintypes import LPCWSTR, UINT_PTR, HANDLE 

# assuming int (* OF_CALLBACK)(int, HANDLE, int, LPCWSTR, UINT_PTR) 
OF_CALLBACK = WINFUNCTYPE(c_int, HANDLE, c_int, LPWCSTR, UINT_PTR) 
def my_callback(handle, namelen, name, context): 
    # do whatever you want with each handle, and whatever other args you get 
my_of_callback = OF_CALLBACK(my_callback) 

OpenFileFinder = windll.OpenFileFinder 
# Might be GetOpenedFilesW, as with most Microsoft DLLs, as explained in docs 
OpenFileFinder.GetOpenedFiles.argtypes = (LPCWSTR, c_int, OF_CALLBACK, UINT_PTR) 
OpenFileFinder.GetOpenedFiles.restype = None 

OpenFileFinder.GetOpenedFiles(ru'C:\Path\To\File\To\Check.txt', 0, my_of_callback, None) 

这很可能是你在回调得到什么实际是指向某种结构,或者你将不得不define-结构列表可能与您直接拨打Nt/Zw功能所需的SYSTEM_HANDLE相同。因此,让我举个例子 - 如果您在回拨中取回SYSTEM_HANDLE *而不是HANDLE,那么它就像这样简单:

class SYSTEM_HANDLE(Structure): 
    _fields_ = [('dwProcessId', DWORD), 
       ('bObjectType', BYTE), 
       ('bFlags', BYTE), 
       ('wValue', WORD), 
       ('pAddress', PVOID), 
       ('GrantedAccess', DWORD)] 

# assuming int (* OF_CALLBACK)(int, SYSTEM_HANDLE *, int, LPCWSTR, UINT_PTR) 
OF_CALLBACK = WINFUNCTYPE(c_int, POINTER(SYSTEM_HANDLE), c_int, LPWCSTR, UINT_PTR) 
+0

我知道确切的程序类名(我使用spyxx.exe来检查它),但pywin32似乎对我来说很难。但我会尝试。 – prehawk

+0

我认为你的意思是窗口类的名字,这根本不会帮你。但是不管你有什么样的信息,它都不会让你的工作变得轻松。没有办法列举每个打开的句柄,然后筛选出你想要的(按流程,按路径,不管)。 – abarnert

+0

@prehawk:另外,在我上面的例子中,我用'ctypes'而不是'pywin32'完成了它。我不知道你是否可以通过'pywin32'访问所需的所有东西,但是如果可以的话,它可能比我的例子容易得多。 – abarnert

相关问题