下載到一半,程式因為任何原因中斷(手動停止、網路斷線、程式崩潰),重新執行時如果沒有任何判斷機制,最簡單的做法就是全部重新下載一次。片段數量一多,這個代價很難忽略。
❌ 反例:檔案存在就跳過
async def save_segment(url, filename):
if os.path.exists(filename):
return # 存在就跳過,但可能只下載了一半
...
如果上次中斷剛好發生在寫入檔案的過程中,這個檔案會存在,但內容不完整。只檢查「存不存在」會誤判成「已經下載完成」,而實際上留下的是一份殘缺的檔案。
✅ 正例:跟遠端宣告的檔案大小比對
async def save_segment(url, filename):
headers = await http_head(url)
expected_size = int(headers['Content-Length'])
actual_size = os.path.getsize(filename) if os.path.exists(filename) else 0
if actual_size == expected_size:
return # 大小吻合,真的下載完成,跳過
# 大小不吻合(包含 0,代表完全沒下載過),重新下載
...
先發一次 HEAD 請求拿到遠端宣告的檔案大小,跟本地檔案實際大小比對——只有兩者吻合才真的視為「已完成」,不吻合(不管是完全沒有還是下載到一半)都當作需要重新下載。
比對檔案大小可以防止「不必要的重複下載」,但它防不了「檔案大小剛好吻合、內容卻是錯的」這種情況——例如來源在下載途中被替換成另一份大小相近但內容不同的資料。這種內容層級的正確性驗證,屬於下一個層次的問題,第三部後段會講到怎麼用其他方式(例如比對片段的媒體資訊)驗證內容本身是不是真的一致,而不只是大小對不對。
你的專案裡有沒有處理過「重新執行時,判斷哪些工作已經完成不用重做」的邏輯?那個判斷依據夠不夠嚴謹,還是只看了「有沒有留下痕跡」?
明天是一個真實案例:合併片段時發現解析度不一致,原來是有不該存在的內容混進了片段清單裡。