在Python中,我如何在二进制文件中读取并循环该文件的每个字节?
当前回答
Python >= 3.8
多亏了walrus操作符(:=),解决方案非常短。我们从文件中读取bytes对象,并将它们赋值给变量byte
with open("myfile", "rb") as f:
while (byte := f.read(1)):
# Do stuff with byte.
Python >= 3
在较旧的Python 3版本中,我们必须使用更详细的方式:
with open("myfile", "rb") as f:
byte = f.read(1)
while byte != b"":
# Do stuff with byte.
byte = f.read(1)
或者像benhoyt说的,跳过不相等,利用b""的值为假的事实。这使得代码在2.6和3之间兼容。X没有任何变化。如果从字节模式转换为文本模式或相反模式,也可以避免更改条件。
with open("myfile", "rb") as f:
byte = f.read(1)
while byte:
# Do stuff with byte.
byte = f.read(1)
Python >= 2.5
在Python 2中,这有点不同。这里我们得到的不是bytes对象,而是原始字符:
with open("myfile", "rb") as f:
byte = f.read(1)
while byte != "":
# Do stuff with byte.
byte = f.read(1)
注意,with语句在Python 2.5以下版本中不可用。要在v 2.5中使用它,你需要导入它:
from __future__ import with_statement
在2.6中不需要这样做。
Python 2.4及更早版本
f = open("myfile", "rb")
try:
byte = f.read(1)
while byte != "":
# Do stuff with byte.
byte = f.read(1)
finally:
f.close()
其他回答
如果要读取大量二进制数据,可能需要考虑struct模块。它被记录为“在C和Python类型之间”转换,但当然,字节就是字节,它们是否被创建为C类型并不重要。例如,如果你的二进制数据包含两个2字节整数和一个4字节整数,你可以这样读取它们(例子来自struct文档):
>>> struct.unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
您可能会发现这比显式遍历文件内容更方便、更快,或者两者兼而有之。
如果你正在寻找一些快速的方法,这里有一个我一直在使用的方法,它已经工作了很多年:
from array import array
with open( path, 'rb' ) as file:
data = array( 'B', file.read() ) # buffer the file
# evaluate it's data
for byte in data:
v = byte # int value
c = chr(byte)
如果你想迭代字符而不是整数,你可以简单地使用data = file.read(),它应该是py3中的bytes()对象。
下面是一个使用Numpy fromfile读取网络端数据的例子:
dtheader= np.dtype([('Start Name','b', (4,)),
('Message Type', np.int32, (1,)),
('Instance', np.int32, (1,)),
('NumItems', np.int32, (1,)),
('Length', np.int32, (1,)),
('ComplexArray', np.int32, (1,))])
dtheader=dtheader.newbyteorder('>')
headerinfo = np.fromfile(iqfile, dtype=dtheader, count=1)
print(raw['Start Name'])
我希望这能有所帮助。问题是fromfile不能识别和EOF,并允许对任意大小的文件优雅地跳出循环。
要读取一个文件-一次一个字节(忽略缓冲)-你可以使用双参数iter(callable, sentinel)内置函数:
with open(filename, 'rb') as file:
for byte in iter(lambda: file.read(1), b''):
# Do stuff with byte
它调用file.read(1),直到没有返回b”(空字节串)。对于大文件,内存不会无限增长。你可以将buffering=0传递给open()来禁用缓冲——它保证每次迭代只读取一个字节(慢)。
With-statement自动关闭文件——包括下面的代码引发异常的情况。
尽管默认情况下存在内部缓冲,但一次处理一个字节的效率仍然很低。例如,下面是黑洞.py实用程序,它会吃掉所有给定的东西:
#!/usr/bin/env python3
"""Discard all input. `cat > /dev/null` analog."""
import sys
from functools import partial
from collections import deque
chunksize = int(sys.argv[1]) if len(sys.argv) > 1 else (1 << 15)
deque(iter(partial(sys.stdin.detach().read, chunksize), b''), maxlen=0)
例子:
$ dd if=/dev/zero bs=1M count=1000 | python3 blackhole.py
在我的机器上,当chunksize == 32768时,它处理大约1.5 GB/s,当chunksize == 1时,它只处理大约7.5 MB/s。也就是说,每次读取一个字节要慢200倍。考虑一下您是否可以重写处理以便一次使用多个字节,以及您是否需要性能。
Mmap允许您同时将文件视为bytearray和文件对象。如果需要访问两个接口,它可以作为在内存中加载整个文件的替代方案。特别是,你可以在一个内存映射文件上一次迭代一个字节,只使用简单的for循环:
from mmap import ACCESS_READ, mmap
with open(filename, 'rb', 0) as f, mmap(f.fileno(), 0, access=ACCESS_READ) as s:
for byte in s: # length is equal to the current file size
# Do stuff with byte
Mmap支持切片表示法。例如,mm[i:i+len]返回文件中从位置i开始的len字节。Python 3.2之前不支持上下文管理器协议;在这种情况下,需要显式调用mm.close()。使用mmap遍历每个字节比file.read(1)消耗更多的内存,但是mmap要快一个数量级。
Python >= 3.8
多亏了walrus操作符(:=),解决方案非常短。我们从文件中读取bytes对象,并将它们赋值给变量byte
with open("myfile", "rb") as f:
while (byte := f.read(1)):
# Do stuff with byte.
Python >= 3
在较旧的Python 3版本中,我们必须使用更详细的方式:
with open("myfile", "rb") as f:
byte = f.read(1)
while byte != b"":
# Do stuff with byte.
byte = f.read(1)
或者像benhoyt说的,跳过不相等,利用b""的值为假的事实。这使得代码在2.6和3之间兼容。X没有任何变化。如果从字节模式转换为文本模式或相反模式,也可以避免更改条件。
with open("myfile", "rb") as f:
byte = f.read(1)
while byte:
# Do stuff with byte.
byte = f.read(1)
Python >= 2.5
在Python 2中,这有点不同。这里我们得到的不是bytes对象,而是原始字符:
with open("myfile", "rb") as f:
byte = f.read(1)
while byte != "":
# Do stuff with byte.
byte = f.read(1)
注意,with语句在Python 2.5以下版本中不可用。要在v 2.5中使用它,你需要导入它:
from __future__ import with_statement
在2.6中不需要这样做。
Python 2.4及更早版本
f = open("myfile", "rb")
try:
byte = f.read(1)
while byte != "":
# Do stuff with byte.
byte = f.read(1)
finally:
f.close()
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用pip3安装包时,“Python中的ssl模块不可用”
- 无法切换Python与pyenv
- Python if not == vs if !=
- 如何从scikit-learn决策树中提取决策规则?
- 为什么在Mac OS X v10.9 (Mavericks)的终端中apt-get功能不起作用?
- 将旋转的xtick标签与各自的xtick对齐
- 为什么元组可以包含可变项?
- 如何合并字典的字典?
- 如何创建类属性?
- 不区分大小写的“in”
- 在Python中获取迭代器中的元素个数
- 解析日期字符串并更改格式
- 使用try和。Python中的if
- 如何在Python中获得所有直接子目录