2

我确定这是非常错误的,而且我遇到了一些问题。我已经将一系列WIN32_FIND_DATAW结构一个接一个地写入磁盘,我想在我的 Python 脚本中使用和解析它们。

我目前使用的代码是:

>>> fp = open('findData', 'r').read()
>>> data = ctypes.cast(fp, ctypes.POINTER(wintypes.WIN32_FIND_DATAW))
>>> print str(data[0].cFileName)

第一个问题是第三行没有像我期望的那样打印一个漂亮的字符串。而不是打印$Recycle.Bin它打印UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)

这是仅打印存储在那里的数据的结果:

>>> data[0].cFileName
u'\U00520024\U00630065\U00630079\U0065006c\U0042002e\U006e0069'

这看起来比较合理。 $是 ASCII 0x24,R是 ASCII 0x52 等等。

那么为什么我不能像字符串一样打印呢?

我的第二个问题是这样做:

>>> data[1].cFileName

给我荒谬的数据。我很确定我没有ctypes.cast正确使用它。我应该怎么做才能访问这些?为了澄清,在 C 中,我只需将PWIN32_FIND_DATAW指针指向缓冲区的开头并使用类似的代码访问数组中的各个结构,我正在尝试在 Python 中做同样的事情。

更新

正在做:

>>> data[0].cFileName.encode('windows-1252')

产生此错误:

UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-5: character maps to <undefined>

更新

第一个条目的开头(data[0]直到 cFileName 的第一部分)如下所示:

user@ubuntu:~/data$ hexdump -C findData | head -n 6
00000000  16 00 00 00 dc 5a 9f d2  31 04 ca 01 ba 81 89 1a  |.....Z..1.......|
00000010  81 e2 cd 01 ba 81 89 1a  81 e2 cd 01 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 24 00 52 00  |............$.R.|
00000030  65 00 63 00 79 00 63 00  6c 00 65 00 2e 00 42 00  |e.c.y.c.l.e...B.|
00000040  69 00 6e 00 00 00 00 00  00 00 00 00 00 00 00 00  |i.n.............|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

如果需要,我可以发布更多数据。

4

2 回答 2

2

正如评论中已经提到的,这是由于 windows 和 linux 之间的差异。该ctypes模块试图适应本地环境,因此不匹配。最好的解决方案是使用struct模块以独立于平台的方式处理它。以下代码显示了如何为单个记录完成此操作。

# Setup test data based on incomplete sample
bytes = "\x16\x00\x00\x00\xdc\x5a\x9f\xd2\x31\x04\xca\x01\xba\x81\x89\x1a\x81\xe2\xcd\x01\xba\x81\x89\x1a\x81\xe2\xcd\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x24\x00\x52\x00\x65\x00\x63\x00\x79\x00\x63\x00\x6c\x00\x65\x00\x2e\x00\x42\x00\x69\x00\x6e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
bytes = bytes + "\x00"*(592-len(bytes))

import struct
import codecs

# typedef struct _WIN32_FIND_DATA {
#   DWORD    dwFileAttributes;
#   FILETIME ftCreationTime;
#   FILETIME ftLastAccessTime;
#   FILETIME ftLastWriteTime;
#   DWORD    nFileSizeHigh;
#   DWORD    nFileSizeLow;
#   DWORD    dwReserved0;
#   DWORD    dwReserved1;
#   TCHAR    cFileName[MAX_PATH];
#   TCHAR    cAlternateFileName[14];


fmt = "<L3Q4L520s28s"

attrs, creation, access, write, sizeHigh, sizeLow, reserved0, reserved1, name, alternateName = struct.unpack(fmt, bytes)
name = codecs.utf_16_le_decode(name)[0].strip('\x00')
alternateName = codecs.utf_16_le_decode(alternateName)[0].strip('\x00')
print name

注意:这假设 MAX_PATH 的大小是 260(这应该是真的,但你永远不知道)。

要从文件中读取所有值,您需要一次读取 592 字节的块,然后按上述方式对其进行解码。

于 2013-03-24T09:44:40.837 回答
0

您应该使用struct标准库http://docs.python.org/2/library/struct.html中的模块,因为您正在解析二进制文件格式。该ctypes模块用于将共享库 (DLL) 与二进制 API 集成到 Python 应用程序中。我并不是说你试图做的事情是不可能的,但是使用ctypes比简单地从二进制文件中解析 C 结构更复杂。

请记住,在 C 中没有 PWIN32_FIND_DATAW 指针之类的东西。这只是一个 typedef,它将解析为原始 C 数据类型之一,例如 32 位指针、64 位指针等。文件中的数据表示原始基本 C 数据类型。

在回答评论...避免寻找捷径。您确实需要深入了解正在写入文件的位以及它们的组织方式。为此,您可能需要做一些 hexdumps 并检查实际的数据表示。根据 MS http://msdn.microsoft.com/en-ca/library/windows/desktop/aa365740(v=vs.85).aspx这不是一个真正复杂的结构。如果 wintypes 中的结构对您不起作用,则可能是您发现了一个错误。磁盘上的结构也可能与内存中的结构不同。通常,in-ram 数据结构包括填充以保持 16 或 64 字节边界上的对齐。但是众所周知,程序员不会按原样转储结构,而是将其分离并输出到一个文件中减去填充。由于 ctypes/wintypes 旨在对 DLL 进行二进制 api 调用,因此其偏向是在数据布局中包含填充。但该文件可能不包含此内容。

于 2013-03-24T09:02:48.617 回答