Python3 讀寫 UTF-16/UTF-16-LE 文字檔

【重點寫在前面】

讀檔時:

  • 用 encoding=’utf-16-le’ 讀取 UTF-16 文字檔時,會誤把檔頭(BOM,也就是’\ufeff’字元)讀進變數裡。
  • 用 encoding=’utf-16′ 讀取 UTF-16-LE 文字檔時,會發生錯誤,無法讀取;因為 python 會期待有一個檔頭。

寫檔時:

  • 用 encoding=’utf-16′ 寫檔時,會自動地在檔案內容前產生一個檔頭,並寫進檔案裡。
  • 用 encoding=’utf-16-le’ 寫檔時,不會自動地產生檔頭。

【看看測試過程】

f16le, f16 = 'utf16le_test.txt', 'utf16_test.txt'
# 產生檔案
with open(f16le, 'w', encoding='utf-16-le') as f1:
    with open(f16, 'w', encoding='utf-16') as f2:
        foo ='\r\n'.join(['abc', '123', '999'])
        f1.write(foo)
        f2.write(foo)
# 用正確的編碼設定來讀檔
with open(f16le, encoding='utf-16-le') as f1:
    with open(f16, encoding='utf-16') as f2:
        b1=f1.readlines()
        b2=f2.readlines()
# 用錯誤的編碼設定來讀檔
with open(f16, encoding='utf-16-le') as f1:
    with open(f16le, encoding='utf-16') as f2:
        c1=f1.readlines()
        c2=f2.readlines()

結果:
b1, b2, c1 皆可正確讀取;c2 無法讀取,有錯誤,Python 會期待 UTF-16 的檔案擁有一個檔頭。

然後,我們可以用下列幾行程式來檢查 Python 會不會將檔頭的字元(‘\ufeff’)讀進變數中:

caption='(首字元長度,首字元)'
print('b1: ', end='')
print('%s = (%s,%s)'%(caption, len(b1[0][0]), b1[0][0]))
print('b2: ', end='')
print('%s = (%s,%s)'%(caption, len(b2[0][0]), b2[0][0]))
print('c1: ', end='')
print('%s = (%s,%s)'%(caption, len(c1[0][0]), c1[0][0]))

輸出結果:
b1: (首字元長度,首字元) = (1,a)
b2: (首字元長度,首字元) = (1,a)
c1: (首字元長度,首字元) = (1,)

也就是說,只有在用 encoding=’utf-16-le’ 讀取 UTF-16 檔案時,才會將檔頭讀進變數中。

然而,就實用層面而言,使用 UTF-16 來寫檔讀檔,python 會自動幫我們處理 BOM 的問題,比較不容易造成使用上的混淆。所以,為了正確的產生 UTF-16 文字檔,下面提供兩種等效的寫檔作法:

body = 'Some text contents\nblah, blah, blah...\netc'
# 作法(一)
with open('file_1.txt', 'w', encoding='utf-16') as f:
    f.write(body)
# 作法(二)
with open('file_2.txt', 'w', encoding='utf-16-le') as f:
    f.write('\ufeff')   # BOM for utf-16
    f.write(body)

# 以後要讀檔時,
# 一率使用 open(filename, 'r', encoding='utf-16')

 
【結論】

  1. 用正確的編碼讀檔時,python3 不會把檔頭讀進變數中。
  2. 用不正確的編碼讀檔時:encoding=’utf-16-le’ 會把 UTF-16 的檔頭(‘\ufeff’)讀進變數中;而encoding=’utf-16′ 無法讀取 UTF-16-LE 文字檔。
  3. 用 encoding=’utf-16′ 寫檔時,會自動地在檔案內容前產生一個檔頭,並寫進檔案裡。
  4. 用 encoding=’utf-16-le’ 寫檔時,不會自動地產生檔頭。

Ref:  http://avidinsight.uk/2016/01/why-python-3-doesnt-write-the-unicode-bom/

廣告

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s