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

Python 文件指標定位:tell() 方法詳解與實戰應用

     編輯:更多程式設計知識

tell() 是 Python 文件物件的「里程表」,隨時回傳目前讀寫游標距離文件開頭的位元組偏移量。雖然單獨看似單純,但結合 seek()、生成器、大文件索引等技術,它是實現高效隨機存取、斷點續傳、流式解析的關鍵基石。本文詳細說明語法、回傳值特性、文字/二進位模式差異與豐富實戰範例。

方法語法

position = file_object.tell()
  • 無參數。
  • 回傳 int:從文件開頭 (0) 算起的位元組位置。

模式差異關鍵表

基礎範例

with open('demo.txt', 'w', encoding='utf-8') as f:
    f.write('Hello')      # 寫入 5 字元
    print(f.tell())       # 5 (UTF-8 各 1 位元組)
    f.write('世界')       # 寫入 2 中文字元 (UTF-8 各 3 位元組)
    print(f.tell())       # 11 (5 + 2*3)

with open('demo.txt', 'r', encoding='utf-8') as f:
    print(f.tell())       # 0
    f.read(1)             # 讀 'H'
    print(f.tell())       # 1
    f.read(1)             # 讀 'e'
    print(f.tell())       # 2

進階實戰應用

1. 大文件斷點續讀:記錄每行起始位置建立索引

class LineIndexer:
    '''建立文件行位移索引,支援 O(1) 隨機存取任意行'''
    def __init__(self, filepath, encoding='utf-8'):
        self.filepath = filepath
        self.encoding = encoding
        self.line_offsets = [0]  # 第 1 行從 0 開始
        
    def build(self):
        with open(self.filepath, 'rb') as f:  # 必須用二進位模式
            while True:
                offset = f.tell()
                line = f.readline()
                if not line:
                    break
                self.line_offsets.append(f.tell())  # 下一行起始位移
        return self
    
    def get_line(self, line_no):  # 1-based
        if not (1 <= line_no < len(self.line_offsets)):
            raise IndexError('行號超出範圍')
        with open(self.filepath, 'rb') as f:
            f.seek(self.line_offsets[line_no - 1])
            return f.readline().decode(self.encoding).rstrip('\n')

# 使用
indexer = LineIndexer('huge_log.txt').build()
print(indexer.get_line(1000000))  # 瞬間讀取第 100 萬行

2. 斷點續傳下載:記錄已寫入位元組數

def download_with_resume(url, dest_path, chunk_size=8192):
    # 1. 取得遠端檔案大小
    head = requests.head(url, allow_redirects=True)
    total_size = int(head.headers.get('Content-Length', 0))
    
    # 2. 檢查本地已下載
    downloaded = os.path.getsize(dest_path) if os.path.exists(dest_path) else 0
    if downloaded >= total_size:
        print('已完整下載')
        return
    
    # 3. 續傳
    headers = {'Range': f'bytes={downloaded}-'}
    with requests.get(url, headers=headers, stream=True) as r:
        with open(dest_path, 'ab') as f:
            f.seek(0, 2)  # 確保在文件結尾
            for chunk in r.iter_content(chunk_size):
                f.write(chunk)
                downloaded += len(chunk)
                print(f'\r進度: {downloaded}/{total_size} ({downloaded*100//total_size}%)', end='')
    print()

3. 流式解析二進位協定:記錄關鍵結構位置

def parse_custom_protocol(filepath):
    '''解析自訂二進位協定:Header(12B) + N 個 Chunk(各 4B 長度 + 資料)'''
    chunks = []
    with open(filepath, 'rb') as f:
        # 讀 Header
        magic, version, chunk_count = struct.unpack('<4sII', f.read(12))
        print(f'Magic: {magic}, Version: {version}, Chunks: {chunk_count}')
        
        for i in range(chunk_count):
            chunk_start = f.tell()  # 記錄 chunk 起始位置
            length, = struct.unpack('

4. 文字模式 tell() 的實際陷阱演示

# 建立測試文件 (含中文、CRLF)
with open('trap.txt', 'w', encoding='utf-8', newline='') as f:
    f.write('第一行\r\n')
    f.write('第二行\r\n')

# 文字模式讀取
with open('trap.txt', 'r', encoding='utf-8') as f:
    print(f'開頭: {f.tell()}')           # 0
    f.readline()                         # 讀 '第一行\n' (CRLF→LF)
    print(f'第1行後: {f.tell()}')        # 9 (邏輯位置: 6字元+1換行+2? 實際不固定)
    f.seek(f.tell())                     # OK: seek 自身 tell 值
    # f.seek(5)                          # OSError! 文字模式不可任意 seek

常數對照:io 模組

import io
# tell() 回傳值可用於 io.SEEK_SET 等常數語境
f.seek(pos, io.SEEK_SET)  # 等同 whence=0

最佳實務總結

  1. 關鍵位置記錄請用二進位模式:'rb'/'wb' 保證 tell() 回傳真實位元組偏移,可任意 seek()。
  2. 文字模式僅用於循序讀寫:不要在文字模式依賴 tell() 做隨機存取邏輯。
  3. 建立索引時一次性掃描:大文件建立行索引只需掃描一次,後續隨機存取極快。
  4. 配合 struct 模組:解析二進位結構時,tell() 記錄每個欄位位置,除錯極方便。
  5. 斷點續傳核心:tell() / os.path.getsize() 取得已傳輸位元組,seek(0, 2) 定位文件尾追加。

tell() 雖小,卻是 Python 文件隨機存取能力的基石。善用它建立索引、實現續傳、解析二進位協定,能讓你的 I/O 代碼從「能跑」進化為「高效、可靠、可擴展」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
模式tell() 回傳值含義精確度可否配合 seek()
'rb'/'wb' (二進位)精確位元組偏移量100%是,任意位置
'r'/'w' (文字)經編碼/換行轉換後的「邏輯位置」不保證對應實體位元組僅限 seek(0) 或 seek(tell值)