如何在 Python 中读取二进制文件

FrontendPro
• 阅读 187

在python中读取一个文本文件相信大家都比较熟悉了,但如果我们遇到一个二进制文件要读取怎么办呢?我们尝试使用 Python 中的内置 open 函数使用默认读取模式读取 zip 文件,抱歉,我们将收到错误消息:

>>> with open("exercises.zip") as zip_file:
...     contents = zip_file.read()
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/usr/lib/python3.10/codecs.py", line 322, in de
code
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8e in position 11: invalid sta
rt byte

我们收到一个错误,是因为 zip 文件不是文本文件,它们是二进制文件。

要从二进制文件中读取,我们需要使用模式 rb 而不是默认模式 rt 打开它:

>>> with open("exercises.zip", mode="rb") as zip_file:
...     contents = zip_file.read()

当从二进制文件中读取时,我们不会得到字符串。将返回一个字节对象,也称为字节字符串:

>>> with open("exercises.zip", mode="rb") as zip_file:
...     contents = zip_file.read()
...
>>> type(contents)
<class 'bytes'>
>>> contents[:20]
b'PK\x03\x04\n\x00\x00\x00\x00\x00Y\x8e\x84T\x00\x00\x00\x00\x00\x00'

字节字符串中没有字符:它们中有字节。

除非我们理解它们的含义,否则文件中的字节对我们没有多大帮助。

使用库来读取二进制文件

处理二进制文件时,你通常会使用和知道如何处理正在使用的特定类型文件的库(内置 Python 库或第三方库)。该库将完成将文件中的字节解码为更易于使用的工作。

例如,Python 的 ZipFile 模块可以帮助我们读取 zip 文件中的数据:

>>> from zipfile import ZipFile
>>>
>>> with ZipFile("exercises.zip") as zip_file:
...     test_file = zip_file.read("exercises/test.py").decode("utf-8")
...
>>> test_file[:30]
'#!/usr/bin/env python3\nfrom __'

如果有人已经完成了这项工作,最好避免实现自己的字节检查或字节操作逻辑。

在 Python 中以字节级别工作

有时你会使用或被要求直接在字节级别工作的库或 API。在这种情况下,你需要至少需要对二进制文件和字节字符串有一点了解。

例如,假设我们要计算给定文件的 sha256 校验和。

在这里,我们有一个名为 get_sha256_hash 的函数来执行此操作:

import hashlib

def get_sha256_hash(filename):
    with open(filename, mode="rb") as f:
        return hashlib.sha256(f.read()).hexdigest()

此函数读取此文件中的所有二进制数据。我们正在读取字节,因为 Python 的 hashlib 模块要求我们使用字节。hashlib 模块在底层工作:它使用字节而不是字符串。

因此,我们传入文件中的所有字节以获取哈希对象,然后对该哈希对象调用 hexdigest 方法以获取表示该文件的 SHA-256 校验和的十六进制字符串:

>>> get_sha256_hash("exercises.zip")
'9e98242a21760945ec815668fc79d8621fa15dd23659ea29be2c5949153fe96d'

此功能运行良好,但使用此功能读取非常大的文件可能会出现问题。

分块读取二进制文件

我们的 get_sha256_hash 函数一次将整个文件读入内存。一个非常大的文件可能会占用大量内存。

对于文本文件,解决此问题的常用方法是逐行读取文件。但是二进制文件不一定有行!但是,我们可以尝试逐块读取。

首先,我们将从文件中读取一个 8 KB 的块:

import hashlib


def get_sha256_hash(filename, buffer_size=2**10*8):
    file_hash = hashlib.sha256()
    with open(filename, mode="rb") as f:
        chunk = f.read(buffer_size)

我们首先创建一个新的哈希对象,然后读取一个 8 KB 的块(通过将字节数传递给我们的文件对象的 read 方法)。

现在我们需要文件的其余部分。所以我们将循环:

import hashlib


def get_sha256_hash(filename, buffer_size=2**10*8):
    file_hash = hashlib.sha256()
    with open(filename, mode="rb") as f:
        chunk = f.read(buffer_size)
        while chunk:
            file_hash.update(chunk)
            chunk = f.read(buffer_size)
    return file_hash.hexdigest()

我们重复读取一个块,更新我们的哈希对象,然后读取另一个块。

只要我们不在文件的末尾,我们就会在读取时返回一个真实的块。

但是当我们在文件的最后读取时,我们会得到一个空字节字符串。空字节字符串(如空字符串)是错误的,因此在文件末尾我们将跳出循环。然后我们将像以前一样返回十六进制摘要。

这个修改后的 get_sha256_hash 函数就像以前一样工作:

>>> get_sha256_hash("exercises.zip")
'9e98242a21760945ec815668fc79d8621fa15dd23659ea29be2c5949153fe96d'

但是,我们现在不是将整个文件读入内存,而是逐块读取文件。

使用赋值表达式

在逐块读取文件时,通常会看到使用的赋值表达式(通过 Python 的海象运算符):

import hashlib


def get_sha256_hash(filename, buffer_size=2**10*8):
    file_hash = hashlib.sha256()
    with open(filename, mode="rb") as f:
        while chunk := f.read(buffer_size):
            file_hash.update(chunk)
    return file_hash.hexdigest()

在 while 循环中重复读取数据是赋值表达式的一个很好的用例。它可能看起来有点奇怪,但它确实为我们节省了几行代码。

注意:海象运算符是在 Python 3.8 中添加的。

最后总结下,当你在 Python 中读取二进制文件时,你会得到字节,当你读取一个大型二进制文件时,你需要逐块读取它,当然如果可以最好避免自己读取二进制文件,有第三方库可以使用第三方库来处理。

觉得Python学习太吃力?分享一份大佬整理的学习资料给你,不管是零基础入门还是想提升Python专业技术都可以免费获取,关注公众号【Python编程学习圈】,回复【学习资料】即可,让你学习更加轻松高效!

点赞
收藏
评论区
推荐文章
CuterCorley CuterCorley
4年前
数据分析 常见异常及解决办法(一)
1.Jupyter读取数据警告ParserWarning:Fallingbacktothe'python'enginebecausethe'c'enginedoesnotsupportregexseparators在使用JupyterNotebook读取数据进行分析时,如下:python<ipythoninput
CuterCorley CuterCorley
4年前
商业数据分析从入门到入职(8)Python模块、文件IO和面向对象
前言本文先介绍了Python中程序、模块和包的基本使用,并在此基础上介绍了Python标准库。然后详细介绍了Python中的文件IO操作,包括文本文件、二进制文件的读写和其他IO操作。最后介绍了面向对象,包括类的定义、继承的使用、鸭子类型和魔法方法。一、程序、模块和包1.自定义模块和包之前我们使用的.ipynb文件都不是纯Python文件,
Easter79 Easter79
3年前
tensorflow 使用队列读取图像文件
原文链接: tensorflow使用队列读取图像文件(https://my.oschina.net/ahaoboy/blog/2252625)读取指定文件夹中的图像文件,使用多进程将文件读取到一个队列中,然后再取参考https://blog.csdn.net/dcrmg/article/details/79776876?utm\_sour
Stella981 Stella981
3年前
Python 操作excel
python操作excel使用xlrd、xlwt和xlutils模块。xlrd模块是读取excel的,xlwt模块是写excel的,xlutils是用来修改excel的一、python 读取excelimportxlrdbookxlrd.open_workbook('all_stu.xls')打开一个excelsheetb
Wesley13 Wesley13
3年前
PHP如何快速读取大文件
PHP如何快速读取大文件在PHP中,对于文件的读取时,最快捷的方式莫过于使用一些诸如file、file\_get\_contents之类的函数,简简单单的几行代码就能很漂亮的完成我们所需要的功能。但当所操作的文件是一个比较大的文件时,这些函数可能就显的力不从心,下面将从一个需求入手来说明对于读取大文件时,常用的操作方法。需求需求有一个
Stella981 Stella981
3年前
Python批量读取文件
importosroot'输入绝对路径'file_namesos.listdir(root)file_ob_listforfile_nameinfile_names:fileobroot'/'file_namefile
Stella981 Stella981
3年前
Python计算大文件行数方法及性能比较
如何使用Python快速高效地统计出大文件的总行数,下面是一些实现方法和性能的比较。1.readline读所有行使用readlines方法读取所有行:defreadline_count(file_name):returnlen(open(file_name).readlines())
Python进阶者 Python进阶者
1年前
读取设置密码保护的excel文件,有没有更好的办法?
大家好,我是Python进阶者。一、前言前几天在Python最强王者交流群【wen】问了一个Python处理Excel加密文件读取问题。问题如下:请教:读取设置了密码保护的exlce文件,dfpd.readexcel(file,password'12345
Python进阶者 Python进阶者
1年前
读取xlsm格式的文件,该表格只有一个,但是通过python读取,却显示两个表格?
大家好,我是皮皮。一、前言前几天在最强王者交流群【wen】问了一个Python处理Excel文件相关的问题,一起来看看吧。请教问题:读取xlsm格式的文件,该表格只有一个名字为"销售明细(2)"的表格,但是通过python读取该文件,却显示两个表格,分别为
小万哥 小万哥
1年前
Python 文件处理指南:打开、读取、写入、追加、创建和删除文件
文件处理是任何Web应用程序的重要部分。Python有多个用于创建、读取、更新和删除文件的函数。文件处理在Python中处理文件的关键函数是open()函数。open()函数接受两个参数:文件名和模式。有四种不同的方法(模式)可以打开文件:"r"读取默认值
小万哥 小万哥
1年前
C 语言文件读取全指南:打开、读取、逐行输出
C语言中的文件读取要从文件读取,可以使用r模式:cFILEfptr;//以读取模式打开文件fptrfopen("filename.txt","r");这将使filename.txt打开以进行读取。在C中读取文件需要一点工作。坚持住!我们将一步一步地指导您。