[閒聊] 在 M$ 環境下讀檔

作者: apua (Apua)   2014-02-27 16:35:04
分享一個這兩天遇到焦頭爛額的問題
在 M$ Windows 上檔名有時會碰到表意文字補充區[1]的字
他不列在 CP950 (Big5) 裡, 可是檔名確實存在該字
如果用 Python os.listdir() 或 Popen('dir',...) 讀出來的話,
會自動轉為 CP950 的同義字 (也就是說該字會被偷偷改成別的字)
.. [1]: http://en.wikipedia.org/wiki/CJK_Compatibility_Ideographs_Supplement
這裡舉一個表意文字的例子::
>>> s = u'\u57fa\uf90a'
>>> print s
基金
>>> s.encode('CP950')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'cp950' codec can't encode character u'\uf90a' in
position 1: illegal multibyte sequence
從 print out 的結果看來, 這個 "金" 字沒有異常
但事實上他根本不是一般的 "金" 字 (正常的 "金" 理應為 u'\u91d1')
在 M$ Windows 上, 如果複製 ``print s`` 的結果存成一個檔名, 將會遇到以下狀況::
>>> import os; A = os.listdir('.'); A
['\xb0\xf2\xaa\xf7']
>>> A[-1].decode('CP950')
u'\u57fa\u91d1'
>>> open(A[-1])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: '\xb0\xf2\xaa\xf7'
顯然原因是 "金" 那個字從根本上被改掉了, 所以檔案找不到
然後? 然後我們設計的程式就爆炸了.....(上百個檔案都有這個字....)
原來正確的作法是 **給予 path 時就使用 unicode** ::
>>> import os; A = os.listdir(u'.'); A
[u'\u57fa\uf90a']
往後所有字串都使用 unicode 操作, 就不會爆炸了
據說事實上 M$ Windows 存檔名就是用 unicode
我還沒找到 "nt" 這個內建的 module 的 source code ,
還不清楚它是 怎麼實作/呼叫哪個函數 的
作者: uranusjr (←這人是超級笨蛋)   2014-02-28 02:03:00
Windows 是用 UTF-16, 不過以微軟的語言這個是叫 Unicode
作者: zha0 (這個帳號是掛網用)   2014-03-01 13:26:00
我以前也遇過, 那時用 python 2.x, 最後用 win32 api 找檔
作者: apua (Apua)   2014-03-03 15:48:00
敢問樓上 win32api 如何取得檔名 (eg: listdir 功能)?因為我們曾試著找過但失敗了 (win32api 文件寫的有點差?)
作者: uranusjr (←這人是超級笨蛋)   2014-03-03 17:58:00
作者: apua (Apua)   2014-03-04 09:41:00
thx

Links booklink

Contact Us: admin [ a t ] ucptt.com