很高興在我寫的文章下看到有人回覆,而後我在測試回覆中的代碼時竟然發現個有趣的現象,而且得出下面的結論,請你們討論測試
r+模式(讀寫)下,若是文件內容已經存在了中文,當你試圖插入新內容時,必須使新內容的整體字節數是當前編碼下單個漢字佔位字節的整數倍。不然讀取時會報錯。
補充:若是你把指針調到末尾則沒這個問題,也就是說能夠在後面寫,可是在前面插入內容的話就會有上面的問題。編碼
爲了搞清楚最底層的工做原理,我專門看了幾篇相關文章,得出以下結論,我以爲能夠了,不用再深究了,再往深了說就有點兒捨本逐末了。
首先,計算機存儲的都是二進制數字,也就是說是每8位一組的0和1的各類組合,當寫入磁盤後,在物理層面這種0和1的組合就固定下來,再往底層說就是磁盤表面會出現凹凸不平的表明0和1的存儲元。(存儲元是存儲器中最小存儲單元,它的做用是用來存放一位二進制代碼0或1。)
因此在文件寫入後這種0和1的組合就固定下來,若是這種組合是用UTF-8編碼寫入的,那麼當你寫入一段漢字後,這種組合就表現爲每24個存儲元表明一個漢字。
此時若是你想修改這段漢字的任何一個字,你必須修改相應的24個存儲元,若是你只修改8個存儲元(一個字節)或者16個存儲元(兩個字節),那麼剩下的存儲元沒法被當前編碼識別,也許碰巧會有某種編碼可以識別這剩下的16個或者8個存儲元表明的組合,但這已經沒有意義。我還不知道有什麼辦法能讓計算機在指定位置使用一種編碼,而後在另外一個位置使用另一種編碼。也許有……暫時還沒學到😄指針
PS:總之,你能夠在R+模式下實現對文件自己的修改,可是每每不會獲得你指望的結果,沒有實際應用意義,即便是修改英文內容,除非你事先知道在確切位置修改確切的內容(好比你想修改19個英文字母,那麼你必須相應地寫入19個新英文字母,若是超過19個的話,它會覆蓋後面的內容)。code
上面的話比較繞口,下面我來根據實際例子說明一下。
首先 咱們用下面的代碼建立一個文件,編碼採用utf-8utf-8
with open('job', mode='w+',encoding='utf-8') as f: f.write('十步殺一人,千里不留行') f.seek(0) print(f.read()) 輸出結果爲: 十步殺一人,千里不留行
而後咱們在r+模式下寫入一個字節的內容:it
with open('job', mode='r+',encoding='utf-8') as f: f.write('1') f.seek(0) print(f.read()) 結果報錯:大意是utf-8編碼沒法解碼。 UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8d in position 1: invalid start byte
最開始我是有些懵逼的,寫入和讀取我都是用的utf-8編碼,怎麼會存在沒法解碼呢?後來我分別測試了2個字節、3個字節、4個字節、5個字節、6個字節的內容後,我恍然大悟,原來必須寫入3的倍數的字節數內容才能夠。io
測試過程以下:原理
with open('job', mode='r+',encoding='utf-8') as f: f.write('aa') f.seek(0) print(f.read()) 結果報錯: UnicodeDecodeError: 'utf-8' codec can't decode byte 0x81 in position 2: invalid start byte
with open('job', mode='r+',encoding='utf-8') as f: f.write('aaa') f.seek(0) print(f.read()) 結果不報錯: aaa步殺一人,千里不留行
with open('job', mode='r+',encoding='utf-8') as f: f.write('aaaa') f.seek(0) print(f.read()) 結果報錯: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xad in position 4: invalid start byte
with open('job', mode='r+',encoding='utf-8') as f: f.write('aaaaa') f.seek(0) print(f.read()) 結果報錯: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa5 in position 5: invalid start byte
with open('job', mode='r+',encoding='utf-8') as f: f.write('aaaaaa') f.seek(0) print(f.read()) 結果不報錯: aaaaaa殺一人,千里不留行
從報錯的結果上來看,若是不是3的倍數,那麼在讀取時你寫入幾個字節就會在第幾個字節處報錯。coding