首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

Python 文件隨機存取:seek() 與 tell() 方法完整教學

     編輯:更多程式設計知識

在 Python 文件操作中,seek() 與 tell() 是實現「隨機存取」的核心雙雄。tell() 回傳目前游標位置,seek() 移動游標到指定位置,兩者結合可實現斷點續傳、二進位結構解析、大文件索引跳躍等進階功能。本文深入解析兩者語法、參數、模式差異與實戰範例。

tell():取得目前游標位置

position = file_object.tell()
  • 回傳整數:從文件開頭算起的位元組偏移量 (0-based)。
  • 文字模式下回傳值可能不等於字元數 (因編碼、換行符轉換)。
  • 二進位模式下精確對應位元組位置。

seek():移動游標位置

file_object.seek(offset, whence=0)

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

常見錯誤與最佳實務

參數說明
offset位移量 (整數),可為負數 (whence=1 或 2 時)。
whence基準點:0=文件開頭 (預設)、1=目前位置、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 的必備內功。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved