windows 哪个进程正在使用给定的文件?

v440hwme  于 2022-11-18  发布在  Windows
关注(0)|答案(2)|浏览(161)

我的一个脚本遇到了问题,它似乎很难写入自己的日志,并抛出错误“此文件正被另一个进程使用”。
我知道有很多方法可以用try excepts来处理这个问题,但是我想找出 * 为什么 * 会发生这种情况,而不是仅仅掩盖它。其他任何东西都不应该访问这个文件。所以为了确认bug的来源,我想找出是什么服务在使用这个文件。
在Windows上的Python中,有没有一种方法可以检查哪个进程正在使用给定的文件?

0lvr5msh

0lvr5msh1#

您可以使用Microsoft的handle.exe命令行实用程序。例如:

import re
import subprocess

_handle_pat = re.compile(r'(.*?)\s+pid:\s+(\d+).*[0-9a-fA-F]+:\s+(.*)')

def open_files(name):
    """return a list of (process_name, pid, filename) tuples for
       open files matching the given name."""
    lines = subprocess.check_output('handle.exe "%s"' % name).splitlines()
    results = (_handle_pat.match(line.decode('mbcs')) for line in lines)
    return [m.groups() for m in results if m]

注意,对于Unicode文件名,这是有限制的。在Python 2中,子进程将name作为ANSI字符串传递,因为它调用CreateProcessA而不是CreateProcessW。在Python 3中,名称作为Unicode传递。在这两种情况下,handle.exe都使用有损的ANSI编码写入其输出,因此结果元组中匹配的文件名可能包含最适合的字符和“?”替换。

3xiyfsfu

3xiyfsfu2#

请不要删除这个答案,以防我做错了什么,但给予我一个机会,通过留下评论来纠正它。谢谢!

有一个比遍历所有PID更好的方法(如评论中所建议的),它涉及到执行Windows API调用来确定给定文件上的所有句柄。请在下面找到我已经发布的另一个问题的代码示例(但是,不能标记为重复,因为它没有任何可接受的答案)。请注意,这只适用于Windows。

import ctypes
from ctypes import wintypes

path = r"C:\temp\stackoverflow39570207.txt"

# -----------------------------------------------------------------------------
# generic strings and constants
# -----------------------------------------------------------------------------

ntdll = ctypes.WinDLL('ntdll')
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

NTSTATUS = wintypes.LONG

INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value
FILE_READ_ATTRIBUTES = 0x80
FILE_SHARE_READ = 1
OPEN_EXISTING = 3
FILE_FLAG_BACKUP_SEMANTICS = 0x02000000

FILE_INFORMATION_CLASS = wintypes.ULONG
FileProcessIdsUsingFileInformation = 47

LPSECURITY_ATTRIBUTES = wintypes.LPVOID
ULONG_PTR = wintypes.WPARAM

# -----------------------------------------------------------------------------
# create handle on concerned file with dwDesiredAccess == FILE_READ_ATTRIBUTES
# -----------------------------------------------------------------------------

kernel32.CreateFileW.restype = wintypes.HANDLE
kernel32.CreateFileW.argtypes = (
    wintypes.LPCWSTR,      # In     lpFileName
    wintypes.DWORD,        # In     dwDesiredAccess
    wintypes.DWORD,        # In     dwShareMode
    LPSECURITY_ATTRIBUTES,  # In_opt lpSecurityAttributes
    wintypes.DWORD,        # In     dwCreationDisposition
    wintypes.DWORD,        # In     dwFlagsAndAttributes
    wintypes.HANDLE)       # In_opt hTemplateFile
hFile = kernel32.CreateFileW(
    path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, None, OPEN_EXISTING,
    FILE_FLAG_BACKUP_SEMANTICS, None)
if hFile == INVALID_HANDLE_VALUE:
    raise ctypes.WinError(ctypes.get_last_error())

# -----------------------------------------------------------------------------
# prepare data types for system call
# -----------------------------------------------------------------------------

class IO_STATUS_BLOCK(ctypes.Structure):
    class _STATUS(ctypes.Union):
        _fields_ = (('Status', NTSTATUS),
                    ('Pointer', wintypes.LPVOID))
    _anonymous_ = '_Status',
    _fields_ = (('_Status', _STATUS),
                ('Information', ULONG_PTR))

iosb = IO_STATUS_BLOCK()

class FILE_PROCESS_IDS_USING_FILE_INFORMATION(ctypes.Structure):
    _fields_ = (('NumberOfProcessIdsInList', wintypes.LARGE_INTEGER),
                ('ProcessIdList', wintypes.LARGE_INTEGER * 64))

info = FILE_PROCESS_IDS_USING_FILE_INFORMATION()

PIO_STATUS_BLOCK = ctypes.POINTER(IO_STATUS_BLOCK)
ntdll.NtQueryInformationFile.restype = NTSTATUS
ntdll.NtQueryInformationFile.argtypes = (
    wintypes.HANDLE,        # In  FileHandle
    PIO_STATUS_BLOCK,       # Out IoStatusBlock
    wintypes.LPVOID,        # Out FileInformation
    wintypes.ULONG,         # In  Length
    FILE_INFORMATION_CLASS)  # In  FileInformationClass

# -----------------------------------------------------------------------------
# system call to retrieve list of PIDs currently using the file
# -----------------------------------------------------------------------------
status = ntdll.NtQueryInformationFile(hFile, ctypes.byref(iosb),
                                      ctypes.byref(info),
                                      ctypes.sizeof(info),
                                      FileProcessIdsUsingFileInformation)
pidList = info.ProcessIdList[0:info.NumberOfProcessIdsInList]
print(pidList)

相关问题