網站首頁 編程語言 正文
在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 中添加的。
原文鏈接:https://juejin.cn/post/7101137971461488677
相關推薦
- 2022-07-09 利用go語言實現查找二叉樹中的最大寬度_Golang
- 2022-04-11 error: failed to push some refs to如何解決
- 2022-04-18 Android申請相機權限和讀寫權限實例_python
- 2024-01-30 在 Jenkins 中使用 SSH Servers 配置文件上傳路徑
- 2022-03-30 聊聊redis-dump工具安裝問題_Redis
- 2022-10-22 Python?NumPy教程之數組的創建詳解_python
- 2022-09-16 Android12四大組件之Activity生命周期變化詳解_Android
- 2022-09-17 python?Pandas之DataFrame索引及選取數據_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支