python迭代通过没有行的二进制文件

时间:2014-12-17 18:52:23

标签: python python-3.x binaryfiles binary-data

我在二进制文件中得到了一些我需要解析的数据。数据被分成22个字节的块,所以我试图生成一个元组列表,每个元组包含22个值。虽然文件没有分隔成行,所以我在弄清楚如何遍历文件并获取数据时遇到了问题。

如果我这样做,它可以正常工作:

nextList = f.read(22)
newList = struct.unpack("BBBBBBBBBBBBBBBBBBBBBB", nextList)

其中newList包含22个值的元组。但是,如果我尝试将类似的逻辑应用于迭代的函数,它就会崩溃。

def getAllData():
    listOfAll = []
    nextList = f.read(22)
    while nextList != "":
        listOfAll.append(struct.unpack("BBBBBBBBBBBBBBBBBBBBBB", nextList))
        nextList = f.read(22)
    return listOfAll

data = getAllData()

给了我这个错误:

Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
data = getAllData()
File "<pyshell#26>", line 5, in getAllData
listOfAll.append(struct.unpack("BBBBBBBBBBBBBBBBBBBBBB", nextList))
struct.error: unpack requires a bytes object of length 22

我对python很新,所以我不太确定我在哪里出错了。我确信文件中的数据均匀分解为22个字节的部分,因此它不是问题。

2 个答案:

答案 0 :(得分:4)

由于您在len(nextList) == 0时报告它正在运行,这可能是因为nextList(不是列表..)是一个空字节对象,它不等于空字符串对象:

>>> b"" == ""
False

所以行中的条件

while nextList != "":
即使nextList为空,

也永远不会成立。这就是使用len(nextList) != 22作为休息条件的原因,甚至是

while nextList:

应该足够了。

答案 1 :(得分:0)

read(22)不保证返回长度为22的字符串。它的合同是从0到22(含)之间的任何地方返回长度字符串。长度为零的字符串表示没有更多数据要读取。在python 3文件对象中生成bytes个对象而不是strstrbytes永远不会被视为平等。

如果您的文件很小,那么您最好将整个文件读入内存,然后将其拆分为块。例如

listOfAll = []
data = f.read()
for i in range(0, len(data), 22):
   t = struct.unpack("BBBBBBBBBBBBBBBBBBBBBB", data[i:i+22])
   listOfAll.append(t)

否则,您需要做一些更复杂的事情,检查您从阅读中获得的数据量。

def dataiter(f, chunksize=22, buffersize=4096):
    data = b''
    while True:
        newdata = f.read(buffersize)    
        if not newdata: # end of file
            if not data:
                return
            else:
                yield data 
                # or raise error  as 0 < len(data) < chunksize
                # or pad with zeros to chunksize
                return

        data += newdata
        i = 0
        while len(data) - i >= chunksize:
            yield data[i:i+chunksize]
            i += chunksize

        try:
            data = data[i:] # keep remainder of unused data
        except IndexError:
            data = b'' # all data was used