在Python中,我如何在二进制文件中读取并循环该文件的每个字节?
当前回答
总结chrispy, Skurmedel, Ben Hoyt和Peter Hansen的所有出色之处,这将是一次一个字节处理二进制文件的最佳解决方案:
with open("myfile", "rb") as f:
while True:
byte = f.read(1)
if not byte:
break
do_stuff_with(ord(byte))
对于python 2.6及以上版本,因为:
Python内部缓冲区-不需要读取块 DRY原则——不重复读行 语句确保干净的文件关闭 当没有更多字节时,'byte'的计算结果为false(当字节为零时不是)
或使用J. F.塞巴斯蒂安的解决方案提高速度
from functools import partial
with open(filename, 'rb') as file:
for byte in iter(partial(file.read, 1), b''):
# Do stuff with byte
或者如果你想把它作为一个生成器函数,就像codeape演示的那样:
def bytes_from_file(filename):
with open(filename, "rb") as f:
while True:
byte = f.read(1)
if not byte:
break
yield(ord(byte))
# example:
for b in bytes_from_file('filename'):
do_stuff_with(b)
其他回答
这个生成器从文件中产生字节,以块的形式读取文件:
def bytes_from_file(filename, chunksize=8192):
with open(filename, "rb") as f:
while True:
chunk = f.read(chunksize)
if chunk:
for b in chunk:
yield b
else:
break
# example:
for b in bytes_from_file('filename'):
do_stuff_with(b)
有关迭代器和生成器的信息,请参阅Python文档。
在尝试了以上所有方法并使用@Aaron Hall的答案后,我在一台运行windows 10, 8gb RAM和Python 3.5 32位的计算机上得到了一个~ 90mb的文件的内存错误。我的一位同事推荐我使用numpy,它的效果非常好。
到目前为止,读取整个二进制文件(我测试过)的最快速度是:
import numpy as np
file = "binary_file.bin"
data = np.fromfile(file, 'u1')
参考
比目前任何方法都要快。希望它能帮助到一些人!
在Python中读取二进制文件并遍历每个字节
Python 3.5的新功能是pathlib模块,它有一个方便的方法,专门以字节的形式读取文件,允许我们遍历字节。我认为这是一个体面的答案(如果快速和肮脏):
import pathlib
for byte in pathlib.Path(path).read_bytes():
print(byte)
有趣的是,这是提到pathlib的唯一答案。
在Python 2中,你可能会这样做(正如Vinay Sajip也建议的那样):
with open(path, 'b') as file:
for byte in file.read():
print(byte)
如果文件太大,无法在内存中遍历,则使用iter函数和可调用的哨兵签名(Python 2版本)对其进行分块:
with open(path, 'b') as file:
callable = lambda: file.read(1024)
sentinel = bytes() # or b''
for chunk in iter(callable, sentinel):
for byte in chunk:
print(byte)
(其他几个答案也提到了这一点,但很少提供合理的读取大小。)
用于大文件或缓冲/交互式读取的最佳实践
让我们创建一个函数来实现这一点,包括Python 3.5+标准库的惯用用法:
from pathlib import Path
from functools import partial
from io import DEFAULT_BUFFER_SIZE
def file_byte_iterator(path):
"""given a path, return an iterator over the file
that lazily loads the file
"""
path = Path(path)
with path.open('rb') as file:
reader = partial(file.read1, DEFAULT_BUFFER_SIZE)
file_iterator = iter(reader, bytes())
for chunk in file_iterator:
yield from chunk
注意,我们使用file.read1。文件。read块,直到它得到它或EOF请求的所有字节。文件。Read1允许我们避免阻塞,因此它可以更快地返回。其他答案也没有提到这一点。
最佳实践使用的演示:
让我们创建一个带有兆字节(实际上是mebibyte)伪随机数据的文件:
import random
import pathlib
path = 'pseudorandom_bytes'
pathobj = pathlib.Path(path)
pathobj.write_bytes(
bytes(random.randint(0, 255) for _ in range(2**20)))
现在让我们遍历它并在内存中物化它:
>>> l = list(file_byte_iterator(path))
>>> len(l)
1048576
我们可以检查数据的任何部分,例如,最后100字节和前100字节:
>>> l[-100:]
[208, 5, 156, 186, 58, 107, 24, 12, 75, 15, 1, 252, 216, 183, 235, 6, 136, 50, 222, 218, 7, 65, 234, 129, 240, 195, 165, 215, 245, 201, 222, 95, 87, 71, 232, 235, 36, 224, 190, 185, 12, 40, 131, 54, 79, 93, 210, 6, 154, 184, 82, 222, 80, 141, 117, 110, 254, 82, 29, 166, 91, 42, 232, 72, 231, 235, 33, 180, 238, 29, 61, 250, 38, 86, 120, 38, 49, 141, 17, 190, 191, 107, 95, 223, 222, 162, 116, 153, 232, 85, 100, 97, 41, 61, 219, 233, 237, 55, 246, 181]
>>> l[:100]
[28, 172, 79, 126, 36, 99, 103, 191, 146, 225, 24, 48, 113, 187, 48, 185, 31, 142, 216, 187, 27, 146, 215, 61, 111, 218, 171, 4, 160, 250, 110, 51, 128, 106, 3, 10, 116, 123, 128, 31, 73, 152, 58, 49, 184, 223, 17, 176, 166, 195, 6, 35, 206, 206, 39, 231, 89, 249, 21, 112, 168, 4, 88, 169, 215, 132, 255, 168, 129, 127, 60, 252, 244, 160, 80, 155, 246, 147, 234, 227, 157, 137, 101, 84, 115, 103, 77, 44, 84, 134, 140, 77, 224, 176, 242, 254, 171, 115, 193, 29]
对于二进制文件,不要逐行迭代
不要做下面的操作——这将拖动任意大小的块,直到它变成一个换行符——当块太小时速度太慢,而且可能也太大了:
with open(path, 'rb') as file:
for chunk in file: # text newline iteration - not for bytes
yield from chunk
以上只适用于语义上人类可读的文本文件(如纯文本、代码、标记、markdown等)。基本上任何ascii, utf,拉丁语等…编码),您应该打开没有'b'标志。
如果文件不是太大,在内存中保存它是一个问题:
with open("filename", "rb") as f:
bytes_read = f.read()
for b in bytes_read:
process_byte(b)
其中process_byte表示希望对传入的字节执行的一些操作。
如果你想一次处理一个数据块:
with open("filename", "rb") as f:
bytes_read = f.read(CHUNKSIZE)
while bytes_read:
for b in bytes_read:
process_byte(b)
bytes_read = f.read(CHUNKSIZE)
with语句在Python 2.5及更高版本中可用。
如果要读取大量二进制数据,可能需要考虑struct模块。它被记录为“在C和Python类型之间”转换,但当然,字节就是字节,它们是否被创建为C类型并不重要。例如,如果你的二进制数据包含两个2字节整数和一个4字节整数,你可以这样读取它们(例子来自struct文档):
>>> struct.unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
您可能会发现这比显式遍历文件内容更方便、更快,或者两者兼而有之。
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用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中获得所有直接子目录