将文件中每4个字节中的3个读入bytearray

时间:2018-08-10 02:45:57

标签: python arrays file micropython

我是python的新手。我目前正在将文件内容读入字节数组,如下所示:

self.palette = bytearray(fp.read(paletteSize*4))

除了读取所有数据,我还需要执行以下操作:

palette[0] = fp.read(1)
palette[1] = fp.read(1)
palette[2] = fp.read(1)
fp.read(1) #throw a byte away
palette[3] = fp.read(1)
# etc thru paletteSize * 4 bytes, resulting in a size * 3 array

基本上,我需要丢弃每个第4个字节,并将其余字节打包到大小为3/4的数组中。

在代码中性能最佳和最干净的最佳方法是什么?我知道我可以像上面那样在范围上进行for循环手动进行此操作,但这看起来确实很丑,并且在python中而不是在本机C代码中涉及很多内存副本。

我问的原因:这是micropython,文件可能有点大(4+ KB),因此节省25%意义重大。

剧透警报:我正在读取位图文件的调色板部分,该文件编码为蓝色,绿色,红色,0x00的四个字节元组-每个调色板条目的第4个字节都是无用数据。

3 个答案:

答案 0 :(得分:3)

由于已经具有调色板大小,因此可以为它预先分配内存,以节省在向其添加数据时扩展字节数组的开销。使用循环一次读取3个字节,然后执行一次搜索以跳过1个字节:

palette = bytearray(paletteSize * 3)
for i in range(paletteSize):
    palette[i * 3: (i + 1) * 3] = fp.read(3)
    fp.seek(1, 1)

答案 1 :(得分:1)

所以今天我了解了Python中的切片分配,这是缺少的魔术。谢谢@blhsing:)

我最终得到了这个版本,该版本避免了循环切片分配中的某些数学运算:

self.palette = bytearray(paletteSize * 3)
   for i in range(0, paletteSize*3, 3):
      self.palette[i : (i + 3)] = fp.read(3)
      fp.seek(1, 1)

添加为答案而不是注释,因为stackoverflow注释格式很烂

答案 2 :(得分:0)

使用struct模块。

s = struct.Struct("BBB")
b = bytearray()
for i in range(paletteSize)
    b.extend(s.unpack_from(f.read(4)))  # b.extend(f.read(4)[:3]) would also work

您甚至可以将其简化为

s = struct.Struct("BBBx" * paletteSize)
b = bytearray(s.unpack(f.read(paletteSize*4)))

尽管我还没有测试过;我从未使用过像这样大的格式字符串,但从理论上讲,它应该可以工作。