【问题标题】:python iterate through binary file without linespython遍历没有行的二进制文件
【发布时间】:2015-02-16 10:09:32
【问题描述】:

我在二进制文件中有一些需要解析的数据。数据被分成 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 个字节的部分,所以这不是问题。

【问题讨论】:

  • 人们“肯定”知道很多事情并非如此。 :-) 为什么不在append 行之前添加print(len(nextList), repr(nextList)),以防万一?另一种可能性是比较失败:read 不返回bytes 对象吗?你确定b"" == ""
  • 我做了你建议的第一件事,虽然它确实像我想的那样均匀分解,但由于某种原因,当 len(nextList) = 0 时它在最后再次运行,所以我只是添加了一个 if if len(nextList) != 22 的 while 循环开始处的语句以中断并且它完全按预期工作。非常感谢,这对我来说是一个愚蠢的错误:)
  • 我建议使用 struct.unpack("22B", nextList) 而不是输入 22 Bs。
  • 我不知道这是我能做的事情(就像我说的,新手),但这确实让事情变得更容易,谢谢!

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


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    >>> b"" == ""
    False
    

    所以你的行中的条件

    while nextList != "":
    

    永远不会是真的,即使nextList 是空的。这就是为什么使用len(nextList) != 22 作为中断条件起作用的原因,甚至

    while nextList:
    

    应该够了。

    【讨论】:

    • 我把它改成了while nextList: 不用if语句也能完美运行,非常感谢!
    猜你喜欢
    • 2016-03-21
    • 2014-05-09
    • 1970-01-01
    • 2021-09-12
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多