2017-05-26 32 views
0

重現步驟:集文件系統編碼蟒3上的英特爾愛迪生

  1. 創建文件test.txt與內容This is 中文(即UTF-8編碼的非ASCII文本)。
  2. 在英特爾Edison上自定義編譯python 3.5.2。
  3. 啓動自定義編譯python3解釋,併發出以下一段代碼:

    with open('test.txt', 'r') as fh: 
        fh.readlines() 
    

實際行爲:

一個UnicodeDecodeError拋出異常。該文件默認打開爲「ASCII」而不是「UTF-8」:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 8: ordinal not in range(128) 

在「常規」 Linux系統這個問題很容易通過設置適當的語言環境來解決,例如見this postthat post。但是,在Intel Edison上,由於默認的Yocto Linux發行版缺少語言環境,因此無法設置LC_CTYPE(請參閱,例如this page)。

我還試圖用其他幾個黑客像

import sys; sys.getfilesystemencoding = lambda: 'UTF-8' 
import locale; locale.getpreferredencoding = lambda: 'utf-8' 

我試着開始Python解釋器之前設置PYTHONIOENCODING=utf8環境變量。

但是,這些都不起作用。唯一的解決方法是將編碼明確指定爲open命令的命令行參數。這適用於上面的代碼片段,但它不會爲我使用的所有軟件包設置系統範圍的默認值(這會隱式地將文件作爲ASCII打開,可能會或可能不會爲我們提供覆蓋默認行爲的方法)。

什麼是設置python解釋器默認文件系統編碼的正確方法? (當然了,無需安裝不需要的系統範圍內的區域設置)

+0

爲什麼不只是使用'open('te st.txt','r',encoding ='utf8')'?顯式比隱式更好。不要使用黑客。 –

+0

'sys.getfilesystemencoding()'不用於確定新打開的文件的編碼。替換'locale.getpreferredencoding'將不起作用,因爲打開文件的* C代碼不會調用Python版本,它可以直接訪問原始的C函數。 –

+0

'PYTHONIOENCODING'適用於'stdin','stdout'和'stderr',而不是'open()'。 –

回答

1

可以設置LC_ALL環境變量來改變默認:

$ python3 -c 'import locale; print(locale.getpreferredencoding())' 
UTF-8 
$ LC_ALL='.ASCII' python3 -c 'import locale; print(locale.getpreferredencoding())' 
US-ASCII 

我測試這兩種在OS X和CentOS 7

至於你的其他嘗試,這是爲什麼他們不工作:

  • sys.getfilesystemencoding()適用於僅文件名(如os.listdir()和朋友)。
  • io模塊實際上並未使用locale.getpreferrredencoding()函數,因此更改模塊上的函數將不起作用。代替使用輕量級的_bootlocale.py bootstrap module。更多關於下面的內容。
  • PYTHONIOENCODING僅適用於sys.stdinsys.stdoutsys.stdstderr

如果設置環境變量的最終失敗,你仍然可以修補_bootlocale模塊:

import _bootlocale 

old = _bootlocale.getpreferredencoding # so you can restore 
_bootlocale.getpreferredencoding = lambda *args: 'UTF-8' 

這又爲我工作(在OS X和CentOS 7,使用3.6測試):

>>> import _bootlocale 
>>> open('/tmp/test.txt', 'w').encoding # showing pre-patch setting 
'UTF-8' 
>>> old = _bootlocale.getpreferredencoding 
>>> _bootlocale.getpreferredencoding = lambda *a: 'ASCII' 
>>> open('/tmp/test.txt', 'w').encoding # gimped hook 
'ASCII' 
+0

我的問題是關於英特爾愛迪生。這是一個嵌入式系統,具有可定製的最小Linux系統,缺少macOS X和Desktop Linux發行版所具有的許多功能。特別是,沒有安裝語言環境,所以設置'LC_ *'只會導致錯誤信息:'-sh:warning:setlocale:LC_ALL:不能更改語言環境(.UTF-8):沒有這樣的文件或目錄' – user8472

+0

@ user8472 :但這只是一個警告。 * Python *有效嗎? –

+0

無論「LC_ALL」環境變量的內容如何,​​python解釋器的輸出總是「ANSI_X3.4-1968」。同樣,解釋器中的「open」命令總是失敗,除非我明確地將編碼設置爲「utf-8」。無論LC_ALL環境變量的值如何,我包括的包中的'open'命令也會重複失敗。 – user8472

相關問題