python - 使用 win32file.ReadFile 读取文件

python - Read file using win32file.ReadFile

类似问题:

What's the correct way to use win32file.ReadFile to get the output from a pipe?

我遇到的问题在那个问题中没有得到解答。当我打电话时

result, data = win32file.ReadFile(my_file, 4096, None)

结果始终为 0,根据文档表示成功:

The result is a tuple of (hr, string/PyOVERLAPPEDReadBuffer), where hr may be 0, 
ERROR_MORE_DATA or ERROR_IO_PENDING.

即使我将缓冲区设置为 10 并且文件大得多,结果也是 0 并且数据是包含前 10 个字符的字符串。

result, buf = win32file.ReadFile(self._handle, 10, None)  
while result == winerror.ERROR_MORE_DATA:            
    result, data = win32file.ReadFile(self._handle, 2048, None)
    buf += data   
    print "Hi"
return result, buf

"Hi" 永远不会打印,即使文件明显包含更多数据。 我遇到的问题是如何确保在不使用可笑的大缓冲区的情况下读取整个文件?

正如已经观察到的那样,如果 win32file.ReadFile 结果值 hr 为 0,则表示成功。这与 win32 api 文档中所说的 0 表示发生错误完全相反。

要确定读取了多少字节,您需要检查返回字符串的长度。如果它与缓冲区大小相同,则可能有更多数据。如果更小,则整个文件已被读取:

def readLines(self):
    bufSize = 4096
    win32file.SetFilePointer(self._handle, 0, win32file.FILE_BEGIN)
    result, data = win32file.ReadFile(self._handle, bufSize, None) 
    buf = data
    while len(data) == bufSize:            
        result, data = win32file.ReadFile(self._handle, bufSize, None)
        buf += data
    return buf.split('\r\n')

您需要为此添加错误处理,例如。检查结果是否为0,如果不是则采取相应措施

使用 PeekNamedPipe 查看管道上还有多少数据要读取。

result, buf = win32file.ReadFile(self._handle, bufSize, None)
_, nAvail, nMessage = win32pipe.PeekNamedPipe(self._handle, 0)
while nAvail > 0:
    result, data = win32file.ReadFile(self._handle, bufSize, None)
    buf += data
    _, nAvail, nMessage = win32pipe.PeekNamedPipe(self._handle, 0)

这将告诉您管道上的数据总量 (nAvail) 以及当前消息剩余要读取的数据量 (nMessage)。然后,您可以使用足够大小的缓冲区来读取剩余的数据,或者如果您愿意,可以分块读取。

如果使用消息模式,您可能希望一次阅读一条消息。如果您无法预测最大消息大小,则首先读取 0 个字节进行阻塞,直到消息可用,然后查询消息大小并读取那么多字节:

# Block until data is available (assumes PIPE_WAIT)
result, _ = win32file.ReadFile(self._handle, 0, None)
# result should be 234
_, nAvail, nMessage = win32pipe.PeekNamedPipe(self._handle, 0)
result, buf = win32file.ReadFile(self._handle, nMessage, None)

如果使用 PIPE_NOWAIT 则使用 PeekNamedPipe 轮询消息并且仅在 nMessage > 0

时读取

我尝试了 beginner_ 的解决方案,并在调用 buf.split('\r\n')

时收到错误消息“需要类似字节的对象,而不是 str”

我打印了 str(buf) 并看到它的形式是“b'bufstring'”

作为黑客,我将行更改为 return str(buf)[2:-1].split('\r\n'),它现在可以正常工作了。