Python中檔案的讀寫、寫讀和追加寫讀三種模式的特點

格瑞姆瑞坡發表於2019-02-16

本文主要討論一下檔案的三種可讀可寫模式的特點及互相之間的區別,以及能否實現修改檔案的操作
由於前文已經討論過編碼的事情了,所以這裡不再研究編碼,所有開啟操作預設都是utf-8編碼(Linux系統下)

首先我們看r+(讀寫)

既然r+既能讀又能寫,那麼能否實現在r+模式下進行檔案的修改呢?答案是肯定的!,但是,有一點你需要注意,除非你知道在確切的位置修改確切的內容,否則往往不會得到你期望的結果。舉個例子如下:
我們有這樣一個文字“十步殺一人,千里不留行”
假設有這樣一個需求,把“十步殺一人”改成“十步殺一個土匪”,初步設想是:用read(4)讀取到漢字“一”,然後寫入漢字“個土匪”:

with open(`job`, mode=`r+`) as f:
    print(`先讀取四個字元:`,f.read(4))
    print(`讀取後的指標位置:`,f.tell())
    f.write(`個土匪`)
    f.seek(0)
    print(f.read())
    輸出為:
    先讀取四個字元: 十步殺一
    讀取後的指標位置: 12
    十步殺一人,千里不留行個土匪

從結果可以看到,使用read(4)指標確實移動到了指定的位置,但是寫入的時候卻沒有按照設想,而是跑到了檔案的末尾。這個原因涉及到一個叫“CHUNK”的東西,俺滴老師沒教,我也不好深說,等深入理解它後再和你們講哈???

那麼我們只說解決辦法,可以用seek()手動定位指標,讓它處在12的位置,然後再寫入:

with open(`job`, mode=`r+`) as f:
    print(`先讀取四個字元:`,f.read(4))
    print(`讀取後的指標位置:`,f.tell())
    f.seek(f.tell())
    f.write(`個土匪`)
    f.seek(0)
    print(f.read())
    輸出:
    先讀取四個字元: 十步殺一
    讀取後的指標位置: 12
    十步殺一個土匪裡不留行

從結果可以看出,它確實是把人字改成了“個土匪”,可是它卻把後面的字給覆蓋了,這完全不是我們想要的結果,那麼為什麼呢?
原因就是:當檔案寫入磁碟後,磁碟會分出一塊空間(實際上應該叫多個儲存元的集合,具體請參考我另外一篇文章),這塊空間是固定的,當你定位指標修改已經存在的內容時,相鄰的後面的內容並不會給你要寫入的內容“讓地方”,也就是說你可以對它進行覆蓋操作,但是你不能讓後面的內容挪地方(這麼說直白不?應該能明白吧。), 因此,雖然我們想要修改的是人這個字,但是由於你寫入了“個土匪”三個字,所以後面的內容被覆蓋了,變成了“十步殺一個土匪裡不留行”。

接下來我們看看w+(寫讀模式)

w+,也就是寫讀操作,仍然對檔案libai2操作,需求還是上例的需求

with open(`libai2`,`w+`) as f:
    content = f.read(25)#讀取25個字元,這其中包括24箇中文漢字或符號 和 一個換行符
    print(`讀取操作後的指標位置:`,f.tell())#指標處在0,那麼意味著檔案內容是空的
    f.write(`五`)#然後我們寫入中文漢字:“五”,期待能覆蓋掉原來的“十”
    print(`寫入操作後的指標位置:`,f.tell())#結果發現指標在3位元組的位置,也就是一個漢字五的後面
    f.seek(0) 
    print(f.read())
讀取操作後的指標位置: 0
寫入操作後的指標位置: 3
五

我們可以看到整個檔案的內容消失了,只有一個漢字“五”
這是因為w開頭的模式會先進行判斷,如果檔案已存在則開啟檔案,並且清空檔案內容。如果該檔案不存在,則建立新檔案。
所以當使用w+這種模式開啟檔案的那一刻,這個檔案原本的內容就已經消失了。

最後我們看看a+(追加寫讀模式)

我們在後臺從新建立了一個libai3檔案,裡面還是隻包含那兩句詩

with open(`libai3`,`a+`) as f: 
        print(`初始指標位置`,f.tell()) 
#初始指標位置是146,48個漢字或字元 加2個換行符,48*3+2=146
#由此可以看出,初始檔案指標處在檔案末尾位置
        f.seek(73) #我們把指標調整到73位元組的位置,也就是漢字“十”的前面
        print(`調整指標在73位元組的位置:`,f.tell())
        f.write(`五`)#然後我們寫入漢字“五”
        f.seek(0) #調整指標到檔案頭部位置
        print(f.read()) #輸出檔案看看發生了什麼
初始指標位置 146
調整指標在73位元組的位置: 73
趙客縵胡纓,吳鉤霜雪明。銀鞍照白馬,颯沓如流星。
十步殺一人,千里不留行。事了拂衣去,深藏身與名。
五

我們發現漢字“五”還是被寫在了檔案末尾

總結

w+和a+無法完成檔案的修改操作,r+可以實現修改的操作,但是結果往往和我們預期的不太一樣,當然,除非你知道要把確切的內容換成確切的新內容,不過感覺這個應用價值不大吧?

相關文章