| 參數 | 說明 |
offset | 位移量 (整數),可為負數 (whence=1 或 2 時)。 |
whence | 基準點:0=文件開頭 (預設)、1=目前位置、2=文件結尾。 |
whence 三種模式圖解
文件內容: A B C D E F G H I J (各 1 位元組)
位置索引: 0 1 2 3 4 5 6 7 8 9
whence=0 (SEEK_SET): seek(3) → 位置 3 (D)
whence=1 (SEEK_CUR): seek(2, 1) 從目前位置+2
whence=2 (SEEK_END): seek(-3, 2) 從結尾倒數 3 位置 (H)
核心範例
1. 斷點續傳下載/上傳核心邏輯
def resume_download(url, local_path):
# 1. 檢查本地已下載大小
downloaded = os.path.getsize(local_path) if os.path.exists(local_path) else 0
# 2. HTTP Range 請求
headers = {'Range': f'bytes={downloaded}-'}
response = requests.get(url, headers=headers, stream=True)
# 3. 追加寫入
with open(local_path, 'ab') as f:
f.seek(0, 2) # 移至文件結尾 (whence=2, offset=0)
for chunk in response.iter_content(8192):
f.write(chunk)
print(f'已續傳 {os.path.getsize(local_path) - downloaded} 位元組')
2. 二進位結構解析 (如解析 BMP/PNG/EXE 標頭)
import struct
def parse_bmp_header(filepath):
with open(filepath, 'rb') as f:
# 讀取前 14 位元組 BITMAPFILEHEADER
f.seek(0)
header = f.read(14)
bfType, bfSize, bfReserved1, bfReserved2, bfOffBits = struct.unpack('<2sIHHI', header)
# 直接跳轉到像素資料起始位置
f.seek(bfOffBits)
pixel_data = f.read(100) # 讀取前 100 位元組像素
print(f'類型: {bfType}, 檔案大小: {bfSize}, 像素偏移: {bfOffBits}')
return pixel_data
3. 建立大文件行索引 (快速隨機存取第 N 行)
def build_line_index(filepath):
'''回傳列表: 每個元素為該行起始位元組位置'''
index = [0]
with open(filepath, 'rb') as f:
while True:
pos = f.tell()
line = f.readline()
if not line:
break
index.append(f.tell()) # 下一行起始位置
return index
def get_line(filepath, line_no, index):
with open(filepath, 'rb') as f:
f.seek(index[line_no - 1])
return f.readline().decode('utf-8').rstrip('\n')
4. 文字模式 seek 的陷阱與解法
# 錯誤示範:文字模式 seek 非 0 或 tell() 回傳值會報錯
with open('text.txt', 'r', encoding='utf-8') as f:
f.seek(5) # OSError: can't do nonzero cur-relative seeks
# 正確做法 1:二進位模式操作位元組位置
with open('text.txt', 'rb') as f:
f.seek(5) # OK
data = f.read(10)
# 正確做法 2:文字模式只能 seek(0) 或 seek(tell_value)
with open('text.txt', 'r', encoding='utf-8') as f:
pos = f.tell()
f.seek(pos) # OK
f.seek(0) # OK
os.SEEK_* 常數 (可讀性更好)
import os
f.seek(0, os.SEEK_SET) # 同 whence=0
f.seek(10, os.SEEK_CUR) # 同 whence=1
f.seek(-20, os.SEEK_END) # 同 whence=2
常見錯誤與最佳實務
| 錯誤 | 原因 | 修正 |
OSError: [Errno 22] Invalid argument | 文字模式 seek 非法位置 | 改用二進位模式 'rb'/'wb',或僅 seek(0) 和 tell() 回傳值 |
| seek 負數超出文件開頭 | offset 過大負值 | 檢查 max(0, f.tell() + offset) |
| tell() 回傳值在文字模式不可靠 | 編碼多位元組字元、換行符轉換 | 關鍵位置記錄請用二進位模式 |
總結:何時使用 seek/tell
- 二進位文件:圖片、影音、壓縮包、資料庫頁面、網路封包 —— 精確位元組控制。
- 大文件索引:建立行位移索引、實現 O(1) 隨機存取行。
- 斷點續傳:記錄已傳輸位元組數,
seek(0, SEEK_END) 追加。
- 記憶體映射替代:
mmap 模組提供更高階的隨機存取介面,底層同樣依賴 seek 概念。
掌握 seek() 與 tell(),讓你的 Python 文件操作從「循序讀寫」進化為「隨機存取」,是處理大數據、二進位協定、高效能 I/O 的必備內功。
- 上一篇文章: Python 文件逐行讀取:readline() 方法完整解析與實戰技巧
- 下一篇文章: Python 文件指標定位:tell() 方法詳解與實戰應用
Copyright ©
程式碼之家 All Rights Reserved