当前位置: 首页 > 后端技术 > Python

Python如何读取二进制文件

时间:2023-03-26 11:38:42 Python

相信大家对Python读取文本文件并不陌生,但是如果遇到二进制文件读取呢?我们尝试使用Python中内置的open函数使用默认读取模式读取zip文件,抱歉,我们收到一条错误消息:>>>withopen("exercises.zip")aszip_file:...contents=zip_文件。read()...Traceback(最近调用最后一次):文件“”,第2行,在文件“/usr/lib/python3.10/codecs.py”,第322行,在解码(result,consumed)=self._buffer_decode(data,self.errors,final)UnicodeDecodeError:'utf-8'codeccan'tdecodebyte0x8einposition11:invalidstartbyte我们得到一个错误,因为zip文件不是文本文件,它们是二进制文件。要从二进制文件中读取,我们需要使用模式rb而不是默认模式rt打开它:>>>withopen("exercises.zip",mode="rb")aszip_file:...contents=zip_file.read()从二进制文件读取时,我们没有得到字符串。将返回一个字节对象,也称为字节字符串:>>>withopen("exercises.zip",mode="rb")aszip_file:...contents=zip_file.read()...>>>type(contents)>>>contents[:20]b'PK\x03\x04\n\x00\x00\x00\x00\x00Y\x8e\x84T\x00\x00\x00\有x00\x00\x00'字节串中没有字符:其中有字节。除非我们理解它们的含义,否则文件中的字节对我们没有多大帮助。使用库读取二进制文件在处理二进制文件时,您通常会使用并知道如何处理您正在使用的特定类型的文件(内置Python库或第三方库)。该库将完成将文件中的字节解码为更易于使用的内容的工作。例如Python的ZipFile模块可以帮助我们读取zip文件中的数据:>>>fromzipfileimportZipFile>>>>>>withZipFile("exercises.zip")aszip_file:...test_file=zip_file.read("exercises/test.py").decode("utf-8")...>>>test_file[:30]'#!/usr/bin/envpython3\nfrom__'如果有人已经完成了这项工作,那就是最好避免实现自己的字节检查或字节操作逻辑。在Python中的字节级工作有时您会使用或被要求直接在字节级使用库或API。在这种情况下,您至少需要了解一点二进制文件和字节字符串的知识。例如,假设我们要计算给定文件的sha256校验和。这里我们有一个名为get_sha256_hash的函数来执行此操作:此文件中的所有二进制数据。我们正在读取字节,因为Python的hashlib模块要求我们使用字节。hashlib模块在底层工作:它使用字节而不是字符串。因此,我们传入文件中的所有字节以获取哈希对象,然后对该哈希对象调用hexdigest方法以获取表示文件SHA-256校验和的十六进制字符串:>>>get_sha256_hash("exercises.zip")'9e98242a21760945ec815668fc79d8621fa15dd23659ea29be2c5949153fe96d'这个函数效果很好,但是用这个函数读取非常大的文件可能会出问题。分块读取二进制文件我们的get_sha256_hash函数一次将整个文件读入内存。非常大的文件会占用大量内存。对于文本文件,解决这个问题的常用方法是逐行读取文件。但是二进制文件不一定有行!但是,我们可以尝试逐块读取。首先,我们将从文件中读取一个8KB的块::chunk=f.read(buffer_size)我们首先创建一个新的哈希对象,然后读取一个8KB的块(通过将字节数传递给文件对象的读取方法)。现在我们需要文件的其余部分。所以我们将循环:importhashlibdefget_sha256_hash(filename,buffer_size=2**10*8):file_hash=hashlib.sha256()withopen(filename,mode="rb")asf:chunk=f.read(buffer_size)whilechunk:file_hash.update(chunk)chunk=f.read(buffer_size)returnfile_hash.hexdigest()我们重复读取一个块,更新我们的哈希对象,然后读取另一个块。只要我们不在文件末尾,我们就会在读取时返回一个真正的块。但是当我们读取文件末尾时,我们得到一个空字节串。空字节字符串(如空字符串)是错误的,因此在文件末尾我们跳出循环。然后我们将像以前一样返回十六进制摘要。这个修改后的get_sha256_hash函数就像以前一样工作:>>>get_sha256_hash("exercises.zip")'9e98242a21760945ec815668fc79d8621fa15dd23659ea29be2c5949153fe96d'然而,我们现在不是将整个文件读入内存,而是逐块读取文件。使用赋值表达式在逐块读取文件时,您经常会看到使用赋值表达式(通过Python的海象运算符):importhashlibdefget_sha256_hash(filename,buffer_size=2**10*8):sha256()withopen(filename,mode="rb")asf:whilechunk:=f.read(buffer_size):file_hash.update(chunk)returnfile_hash.hexdigest()在while循环中重复读取数据是一个赋值表达式的一个很好的用例。它可能看起来有点奇怪,但它确实为我们节省了几行代码。注意:walrus运算符是在Python3.8中添加的。总结一下,当你在Python中读取一个二进制文件时,你得到的是字节,当你读取一个大的二进制文件时,你需要逐块读取它,当然如果可以的话最好避免自己读取二进制文件,有是可以使用第三方库处理的第三方库。觉得Python太难学?分享一份大佬给大家整理的学习资料。无论是零基础入门,还是想提升Python专业技能,都可以免费获取。关注公众号【Python编程学习圈】,回复【学习资料】,让你学习更轻松,更高效!