前言
此前遇到過UTF8格式的文件有無BOM的導致的問題,最近在做自動化測試,讀寫配置文件時又遇到類似的問題,和此前一樣,又是折騰了挺久之后,通過工具比較才知道原因。
兩次在一個問題上面栽更頭,就在想有沒有一個一勞永逸的方法避免這個問題,或者能做到檢測,不用到最后借助Beyond Compare進行16進制比較。
之前的博客中UTF8格式的文件有無BOM做了比較詳細的說明,有興趣的可以看看:
UTF-8文件的Unicode簽名BOM(Byte Order Mark)問題記錄(EF BB BF)
Python codecs
此前很少使用codecs,查閱了相關資料知道這個是一個好東西。
比如說當我們有數據要保存的時候,大多數時候會選擇保存到TXT中,當然數據量大的時候,保存到數據庫還是比較方便,然后在網絡傳輸的時候需要序列號、json化。
而我們操作txt平常用得最多的就是open內置函數,或者file這個工廠函數,兩者效果基本一樣。
但是我們用open方法打開文件有時候會有一些問題,因為open打開文件只能寫入str類型,而不會管字符串是什么編碼方式。
例如這樣是可以的,示例:
>>> fr = open('test.txt','a')
>>> line1 = "我愛祖國"
>>> fr.write(line1)
但是有時候我們爬蟲或者其他方式得到一些數據寫入文件時會有編碼不統一的問題,此時寫入open方式打開的文件就有問題了。示例:
>>> line2 = u'我愛祖國'
>>> fr.write(line2)
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
fr.write(line2)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-11: ordinal not in range(128)
怎么辦?我們可以將上面的line2編碼成str類型。
操作步驟:先把原數據decode為unicode再encode為str,太麻煩了。。。
input文件(gbk, utf-8...) ----decode-----> unicode -------encode------> output文件(gbk, utf-8...)
其實Python提供了更簡單的做法,那就是今天的主角codecs.open,示例:
>>> import codecs
>>> fw = codecs.open('test1.txt','a','utf-8')
>>> fw.write(line2)
>>>
沒有報錯,寫入成功!
其實Python對多國語言的處理是支持的很好的,它可以處理當下任意編碼的字符。
有一點需要清楚的是,當python要做編碼轉換的時候,會借助於內部的編碼,轉換過程是這樣的:
原有編碼 -> 內部編碼 -> 目的編碼
而codecs提供的方法可以指定一個編碼打開文件,使用這個方法打開的文件讀取返回的將是unicode。寫入時,如果參數是unicode,則使用open()時指定的編碼進行編碼后寫入;如果是str,則先根據源代碼文件聲明的字符編碼,解碼成unicode后再進行前述 操作。相對內置的open()來說,這個方法不容易在編碼上出現問題。所以,推薦大家在文件讀寫的時候使用codecs
檢測及消除BOM
然后繼續我們今天的另外一個主題,怎么樣消除UTF-8文件中的名BOM(Byte Order Mark),十六進制編碼(EF BB BF),博主的方法有些取巧但是也比較高效,主要用到了codecs的函數BOM_UTF8,如果發現BOM_UTF8,則直接改寫文件內容。
示例代碼:
import codecs
with open(config_path) as source_file:
data = source_file.read()
# remove BOM
if data[:3] == codecs.BOM_UTF8: # 判斷是否為帶BOM文件
data = data[3:]
with codecs.open(config_path) as dest_file:
dest_file.write(data)
相關讀寫模式
codecs有如下的讀寫模式,和open用法基本一致。
模式 | 描述 |
---|---|
r | 僅讀,待打開的文件必須存在 |
w | 僅寫,若文件已存在,內容將先被清空 |
a | 僅寫,若文件已存在,內容不會清空 |
r+ | 讀寫,待打開的文件必須存在 |
w+ | 讀寫,若文件已存在,內容將先被清空 |
a+ | 讀寫,若文件已存在,內容不會清空 |
rb | 僅讀,二進制,待打開的文件必須存在 |
wb | 僅寫,二進制,若文件已存在,內容將先被清空 |
ab | 僅寫,二進制,若文件已存在,內容不會清空 |
r+b | 讀寫,二進制,待打開的文件必須存在 |
w+b | 讀寫,二進制,若文件已存在,內容將先被清空 |
a+b | 讀寫,二進制,若文件已存在,內容不會清空 |
相關資料:
https://www.cnblogs.com/buptldf/p/4805879.html