Python中幾種高效讀取大文件的完整指南
在處理大型文件時(如內(nèi)存只有4G卻要讀取8G的文件),我們需要采用特殊的技術(shù)來避免內(nèi)存溢出。以下是幾種高效讀取大文件的方法。
一、基本方法:逐行讀取
1. 使用文件對象的迭代器
最簡單的方法是直接迭代文件對象,Python會自動使用緩沖IO以高效的方式處理:
with open('large_file.txt', 'r', encoding='utf-8') as f: for line in f: # 逐行讀取,內(nèi)存友好 process_line(line) # 處理每一行
2. 明確使用 readline()
with open('large_file.txt', 'r') as f: while True: line = f.readline() if not line: # 到達(dá)文件末尾 break process_line(line)
二、分塊讀取方法
對于非文本文件或需要按塊處理的情況:
1. 指定緩沖區(qū)大小
BUFFER_SIZE = 1024 * 1024 # 1MB的緩沖區(qū) with open('large_file.bin', 'rb') as f: while True: chunk = f.read(BUFFER_SIZE) if not chunk: # 文件結(jié)束 break process_chunk(chunk)
2. 使用 iter 和 partial
更Pythonic的分塊讀取方式:
from functools import partial chunk_size = 1024 * 1024 # 1MB with open('large_file.bin', 'rb') as f: for chunk in iter(partial(f.read, chunk_size), b''): process_chunk(chunk)
三、內(nèi)存映射文件 (mmap)
對于需要隨機訪問的大型文件:
import mmap with open('large_file.bin', 'r+b') as f: # 創(chuàng)建內(nèi)存映射 mm = mmap.mmap(f.fileno(), 0) # 像操作字符串一樣操作文件 print(mm[:100]) # 讀取前100字節(jié) # 可以搜索內(nèi)容 index = mm.find(b'some_pattern') if index != -1: print(f"Found at position {index}") mm.close() # 記得關(guān)閉映射
四、使用生成器處理
將文件處理邏輯封裝為生成器:
def read_large_file(file_path, chunk_size=1024*1024): """生成器函數(shù),逐塊讀取大文件""" with open(file_path, 'rb') as f: while True: chunk = f.read(chunk_size) if not chunk: break yield chunk # 使用生成器 for chunk in read_large_file('huge_file.bin'): process_chunk(chunk)
五、處理壓縮文件
對于大型壓縮文件,可以使用流式解壓:
1. gzip 文件
import gzip import shutil with gzip.open('large_file.gz', 'rb') as f_in: with open('large_file_extracted', 'wb') as f_out: shutil.copyfileobj(f_in, f_out) # 流式復(fù)制
2. zip 文件
import zipfile with zipfile.ZipFile('large_file.zip', 'r') as z: with z.open('file_inside.zip') as f: for line in f: process_line(line)
六、多線程/多進(jìn)程處理
對于需要并行處理的情況:
1. 多線程處理不同塊
from concurrent.futures import ThreadPoolExecutor import os def process_chunk(start, end, file_path): """處理文件的指定部分""" with open(file_path, 'rb') as f: f.seek(start) chunk = f.read(end - start) # 處理chunk... def parallel_file_processing(file_path, num_threads=4): file_size = os.path.getsize(file_path) chunk_size = file_size // num_threads with ThreadPoolExecutor(max_workers=num_threads) as executor: futures = [] for i in range(num_threads): start = i * chunk_size end = start + chunk_size if i != num_threads - 1 else file_size futures.append(executor.submit(process_chunk, start, end, file_path)) # 等待所有任務(wù)完成 for future in concurrent.futures.as_completed(futures): future.result()
七、使用第三方庫
1. Dask - 用于超大型數(shù)據(jù)集
import dask.dataframe as dd # 創(chuàng)建延遲計算的DataFrame df = dd.read_csv('very_large_file.csv', blocksize=25e6) # 25MB每塊 # 執(zhí)行操作(惰性計算) result = df.groupby('column').mean().compute() # 實際計算
2. PyTables - 處理HDF5格式
import tables # 打開HDF5文件 h5file = tables.open_file('large_data.h5', mode='r') # 訪問數(shù)據(jù)集 table = h5file.root.data.table for row in table.iterrows(): # 迭代訪問 process_row(row) h5file.close()
八、數(shù)據(jù)庫替代方案
對于需要頻繁查詢的大型數(shù)據(jù),考慮使用數(shù)據(jù)庫:
1. SQLite
import sqlite3 # 將數(shù)據(jù)導(dǎo)入SQLite conn = sqlite3.connect(':memory:') # 或磁盤數(shù)據(jù)庫 cursor = conn.cursor() cursor.execute('CREATE TABLE data (col1, col2, col3)') # 批量插入數(shù)據(jù) with open('large_file.csv') as f: # 使用生成器避免內(nèi)存問題 data_gen = (line.strip().split(',') for line in f) cursor.executemany('INSERT INTO data VALUES (?, ?, ?)', data_gen) conn.commit()
九、性能優(yōu)化技巧
緩沖區(qū)大小選擇:
- 通常8KB到1MB之間效果最好
- 可通過實驗找到最佳大小
二進(jìn)制模式 vs 文本模式:
- 二進(jìn)制模式(
'rb'
)通常更快 - 文本模式(
'r'
)需要處理編碼,但更方便
- 二進(jìn)制模式(
操作系統(tǒng)緩存:
- 現(xiàn)代OS會自動緩存頻繁訪問的文件部分
- 多次讀取同一大文件時,第二次會快很多
避免不必要的處理:
- 盡早過濾掉不需要的數(shù)據(jù)
- 使用生成器保持內(nèi)存效率
十、完整示例:處理超大CSV文件
import csv from collections import namedtuple from itertools import islice def process_large_csv(file_path, batch_size=10000): """分批處理大型CSV文件""" # 定義行結(jié)構(gòu) CSVRow = namedtuple('CSVRow', ['id', 'name', 'value']) with open(file_path, 'r', encoding='utf-8') as f: reader = csv.reader(f) headers = next(reader) # 跳過標(biāo)題行 while True: # 讀取一批行 batch = list(islice(reader, batch_size)) if not batch: break # 文件結(jié)束 # 處理批次 rows = [CSVRow(*row) for row in batch] process_batch(rows) # 可選:顯示進(jìn)度 print(f"Processed {len(batch)} rows") def process_batch(rows): """處理一批數(shù)據(jù)""" # 這里添加實際處理邏輯 pass # 使用 process_large_csv('huge_dataset.csv')
十一、總結(jié)
處理大文件的關(guān)鍵原則:
- 不要一次性加載到內(nèi)存:始終使用迭代或分塊方式
- 選擇合適的數(shù)據(jù)結(jié)構(gòu):根據(jù)需求選擇逐行、分塊或內(nèi)存映射
- 考慮并行處理:對于CPU密集型處理
- 利用生成器:保持內(nèi)存效率
- 考慮專業(yè)工具:如Dask、PyTables等
通過以上技術(shù),即使內(nèi)存有限,也能高效處理遠(yuǎn)大于內(nèi)存的文件。記住,正確的I/O策略可以顯著影響程序性能,特別是對于大型數(shù)據(jù)集。
到此這篇關(guān)于Python中幾種高效讀取大文件的完整指南的文章就介紹到這了,更多相關(guān)Python 讀取大文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python selenium鍵盤鼠標(biāo)事件實現(xiàn)過程詳解
這篇文章主要介紹了Python selenium鍵盤鼠標(biāo)事件實現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-07-07Python?Pandas讀取csv/tsv文件(read_csv,read_table)的區(qū)別
這篇文章主要給大家介紹了關(guān)于Python?Pandas讀取csv/tsv文件(read_csv,read_table)區(qū)別的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Pandas具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-01-01Pytorch 實現(xiàn)計算分類器準(zhǔn)確率(總分類及子分類)
今天小編就為大家分享一篇Pytorch 實現(xiàn)計算分類器準(zhǔn)確率(總分類及子分類),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-01-01python GUI庫圖形界面開發(fā)之PyQt5簡單繪圖板實例與代碼分析
這篇文章主要介紹了python GUI庫圖形界面開發(fā)之PyQt5簡單繪圖板實例與代碼分析,需要的朋友可以參考下2020-03-03Python中random.choice()函數(shù)的使用
random.choice()?是 Python 標(biāo)準(zhǔn)庫?random?模塊中的一個函數(shù),用于從一個?非空序列?中?隨機選擇一個元素,本文主要介紹了Python中random.choice()函數(shù)的使用,具有一定的參考價值,感興趣的可以了解一下2025-04-04python GUI庫圖形界面開發(fā)之PyQt5布局控件QHBoxLayout詳細(xì)使用方法與實例
這篇文章主要介紹了python GUI庫圖形界面開發(fā)之PyQt5布局控件QHBoxLayout詳細(xì)使用方法與實例,需要的朋友可以參考下2020-03-03