利用Python中的内置open函数读取二进制文件
作者:??Python编程学习圈???? 发布时间:2022-02-26 21:00:47
在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("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 中读取二进制文件时,你会得到字节,当你读取一个大型二进制文件时,你需要逐块读取它,当然如果可以最好避免自己读取二进制文件,有第三方库可以使用第三方库来处理。
来源:https://juejin.cn/post/7101137971461488677


猜你喜欢
- 前言我想大家都玩过诺基亚上面的贪吃蛇吧,本文将带你一步步用python语言实现一个snake小游戏。基本环境配置版本:Python3系统:W
- tensorflow升级到1.0之后,增加了一些高级模块: 如tf.layers, tf.metrics, 和tf.losses,使得代码稍
- 一、 通过runtime包进行多核设置1.NumCPU()获取当前系统的cpu核数2.GOMAXPROCS设置当前程序运行时占用的cpu核数
- 为什么需要协程协程的本质是将一段数据的运行状态进行打包,可以在线程之间调度,所以协程就是在单线程的环境下实现的应用程序级别的并发,就是把本来
- 引言关键!!!!使用loc函数来查找。话不多说,直接演示:有以下名为try.xlsx表:1.根据index查询条件:首先导入的数据必须的有i
- 简介由于项目在注册、登录、找回密码 时需要发送短信验证的功能,我们使用腾讯云短信做。为什么要用腾讯云短信呢? 因为注册就送 100条免费短信
- 在我们的日常工作自动化测试当中,几乎超过一半的功能都需要利用定时的任务来推动触发,例如在我们项目中有一个定时监控模块,根据自己设置的频率定时
- 本文实例讲述了Python使用xlrd模块操作Excel数据导入的方法。分享给大家供大家参考。具体分析如下:xlrd是一个基于python的
- 本文实例为大家分享了python创建单词词库的具体代码,供大家参考,具体内容如下基本思路:以COCA两万单词表为基础,用python爬取金山
- 前言IP地址是指互联网协议地址(英语:Internet Protocol Address,又译为网际协议地址),是IP Address的缩写
- 在 Python中,认为以下值为假:None # None值False # False值0 # 数值零不管它是int,float还是comp
- 本文实例讲述了Python实现的数据结构与算法之队列。分享给大家供大家参考。具体分析如下:一、概述队列(Queue)是一种先进先出(FIFO
- 服务器现在同时输出json和xml两种数据,取决于服务程序和页面之间的约定。在程序遇到问题的时候会返回错误信息,也按照相同的约定会返回jso
- MySQL数据库恢复到指定时间点时,我们必须通过MySQL全备+MySQL增量备份(可选)+MySQL的二进制日志(binlog)进行重放来
- Python面向对象编程(一)Python面向对象编程(二)Python面向对象编程(三)一、isinstance和issubclassty
- 本文实例讲述了Zend Framework生成验证码并实现验证码验证功能的方法。分享给大家供大家参考,具体如下:今天讲述如何在留言本中实现验
- 微信支付、支付宝等第三方支付,需要和银联、网联对接,有清算机构和银行的交易处理通道成本。下文说的费率是指支付手续费的费率,在用户支付的时候,
- 目录Tornado是什么安装试试看使用tornado框架来写一个web application总结Tornado是什么学委之前在看Jupyt
- 引文之前将PHP反序列化的基础知识讲了一遍,不知道大家学习的怎么样了,今天给大家带来PHP反序列化的进阶知识:PHAR反序列化,也是之前本人
- python使用ctypes模块调用windows api GetVersionEx获取当前系统版本,没有使用python32#!c:/py