1

所以我试图遍历 tar 中的多个文件,然后将这些数据加载到我定义的一些 ctype 结构中。这对非 tar 文件运行良好,但后来我发现tarfile 的方法返回的ExFileObjectextractfile(member)不支持该.readinto(b)方法。

所以现在这就是我正在做的事情:

import os
import tarfile
import io
from ctypes import c_uint, c_char, c_ubyte, c_ushort, BigEndianStructure

class MyStructure(BigEndianStructure):
    _pack_ = True
    _fields_ = [
                ("id", c_uint), # 4 bytes
                ("namefield", c_char * 32), # 32 bytes
                ("timestamp", c_ubyte * 4), # 4 bytes
                ("payload_length", c_ushort), # 2 bytes
                ]  


def process_tar(tar_files):
    """
    untar and return file objects to be parsed
    """
    for filepath in tar_files:
        f = os.path.abspath(filepath)
        with tarfile.open(f, 'r:*') as tar_f:
            #tar_f.fileobject = io.BufferedReader
            for tarinfo_member in tar_f.getmembers():
                if tarinfo_member.isfile():
                    yield tar_f.extractfile(tarinfo_member)

f = "somefiles.tar.gz"                
for tar_member_fileobj in process_tar([f]):
    mystruct = MyStructure()
    tar_member_fileobj.readinto(mystruct)

得到这个:

---------------------------------------------------------------------------  AttributeError                            Traceback (most recent call last) <ipython-input-4-257ee4b46c31> in <module>()
     29 for tar_member_fileobj in process_tar([f]):
     30     mystruct = MyStructure()
---> 31     tar_member_fileobj.readinto(mystruct)

AttributeError: 'ExFileObject' object has no attribute 'readinto'

有没有办法将此方法添加到 ExFileObject 中?或者,是否有另一种方法可以轻松地将我的数据加载到我定义的 ctypes 结构中?我注意到在tarfile对象中,您可以设置fileobject用于返回的 tarinfo 文件,但只是交换 io.BufferedReader 似乎不起作用。

(我尝试将 ExFileObject 读入 StringIO,但它似乎也没有readinto()正确实现......我想我可以只extractall()到内存中的文件空间并将文件作为标准文件对象重新打开,但我会想避免这种情况,因为我需要额外的配置)

4

1 回答 1

1

ExFileObject没有获利readinto的方法,但您仍然可以通过读取文件的标题read并使用以下方法将数据复制到结构中来做到这一点memmove

memmove(byref(mystruct),
        tar_member_fileobj.read(sizeof(mystruct)),
        sizeof(mystruct)
)

例如:

import os
import tarfile
import io
from ctypes import *

class MyStructure(BigEndianStructure):
    _pack_ = True
    _fields_ = [
                ("id", c_uint), # 4 bytes
                ("namefield", c_char * 32), # 32 bytes
                ("timestamp", c_ubyte * 4), # 4 bytes
                ("payload_length", c_ushort), # 2 bytes
                ]  


def process_tar(tar_files):
    """
    untar and return file objects to be parsed
    """
    for filepath in tar_files:
        f = os.path.abspath(filepath)
        with tarfile.open(f, 'r:*') as tar_f:
            #tar_f.fileobject = io.BufferedReader
            for tarinfo_member in tar_f.getmembers():
                if tarinfo_member.isfile():
                    yield tar_f.extractfile(tarinfo_member)



# test tar.gz file
open('somefiles.tar.gz', 'wb').write(
'\x1f\x8b\x08\x08\xad\x5c\x34\x52\x02\x00\x66\x6f\x6f\x2e\x74\
\x61\x72\x00\xed\xca\x49\x0a\x83\x40\x14\x04\xd0\x7f\x85\xdc\
\xa0\x43\x92\x6d\xf8\xdd\xa6\xed\x6d\xe6\xc9\x79\x1e\x76\x82\
\x0a\x82\x4b\xef\x8f\xf6\x42\xf0\x02\x6e\xe4\xbf\x4d\x41\x55\
\xb5\x5d\xdf\x9c\xeb\x6a\xa8\x60\x3d\x1c\x51\x29\xc5\x80\x69\
\xb8\xc8\x99\x14\x8c\x0b\xc1\x25\x4a\x53\x5c\x4c\x5d\x28\x9c\
\xfe\x08\x64\x6d\xbb\xc9\xed\xfe\x78\xbe\xde\x9f\xef\xef\x6f\
\xd9\x8e\xeb\xf9\x41\x18\xc5\x49\x9a\xe5\x45\xb9\xbf\x1e\x8e\
\x27\xd0\xbb\x61\x00\x21\x84\x90\x0d\x19\x01\xd4\xe8\x88\xcf\
\x00\x08\x00\x00'
)

f = "somefiles.tar.gz"                
for tar_member_fileobj in process_tar([f]):
    mystruct = MyStructure()

    memmove(byref(mystruct),
            tar_member_fileobj.read(sizeof(mystruct)),
            sizeof(mystruct)
    )

    print hex(mystruct.id)
    print mystruct.namefield
    print ''.join(map(chr, mystruct.timestamp))
    print hex(mystruct.payload_length)

该字符串\x1f\x8b\x08\x08\xad ...是一个 tar.gz 文件,其中包含:

\x11\x11\x11\x11ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%\x00ABCD33

将该数据复制到其中后mystruct应打印:

0x11111111L
ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%
ABCD
0x3333
于 2013-09-14T13:28:04.617 回答