《Python Cookbook 3rd》笔记(5.15):打印不合法的文件名
打印不合法的文件名
問題
你的程序獲取了一個目錄中的文件名列表,但是當它試著去打印文件名的時候程序崩潰,出現了 UnicodeEncodeError 異常和一條奇怪的消息—— surrogates not allowed 。
解法
當打印未知的文件名時,使用下面的方法可以避免這樣的錯誤:
def bad_filename(filename):return repr(filename)[1:-1]try:print(filename) except UnicodeEncodeError:print(bad_filename(filename))討論
這一小節討論的是在編寫必須處理文件系統的程序時一個不太常見但又很棘手的問題。默認情況下,Python假定所有文件名都已經根據sys.getfilesystemencoding()的值編碼過了。但是,有一些文件系統并沒有強制要求這樣做,因此允許創建文件名沒有正確編碼的文件。這種情況不太常見,但是總會有些用戶冒險這樣做或者是無意之中這樣做了(可能是在一個有缺陷的代碼中給open()函數傳遞了一個不合規范的文件名)。
當執行類似os.listdir()這樣的函數時,這些不合規范的文件名就會讓Python陷入困境。一方面,它不能僅僅只是丟棄這些不合格的名字。而另一方面,它又不能將這些文件名轉換為正確的文本字符串。Python對這個問題的解決方案是從文件名中獲取未解碼的字節值比如\xhh并將它映射成Unicode字符\udchh表示的所謂的“代理編碼”。下面一個例子演示了當一個不合格目錄列表中含有一個文件名為 b?d.txt(使用Latin-1而不是UTF-8編碼)時的樣子:
>>> import os >>> files = os.listdir('.') >>> files ['spam.py', 'b\udce4d.txt', 'foo.txt'] >>>如果你有代碼需要操作文件名或者將文件名傳遞給 open() 這樣的函數,一切都能正常工作。只有當你想要輸出文件名時才會碰到些麻煩 (比如打印輸出到屏幕或日志文件等)。特別的,當你想打印上面的文件名列表時,你的程序就會崩潰:
>>> for name in files: ... print(name) ... spam.py Traceback (most recent call last):File "<stdin>", line 2, in <module> UnicodeEncodeError: 'utf-8' codec can't encode character '\udce4' in position 1: surrogates not allowed >>>程序崩潰的原因就是字符 nudce4 是一個非法的 Unicode 字符。它其實是一個被稱為代理字符對的雙字符組合的后半部分。由于缺少了前半部分,因此它是個非法的Unicode。所以,唯一能成功輸出的方法就是當遇到不合法文件名時采取相應的補救措施。比如可以將上述代碼修改如下:
>>> for name in files: ... try: ... print(name) ... except UnicodeEncodeError: ... print(bad_filename(name)) ... spam.py b\udce4d.txt foo.txt >>>在 bad_filename() 函數中怎樣處置取決于你自己。另外一個選擇就是通過某種方式重新編碼,示例如下:
def bad_filename(filename):temp = filename.encode(sys.getfilesystemencoding(), errors='surrogateescape')return temp.decode('latin-1')surrogateescape:這種是 Python 在絕大部分面向 OS 的 API 中所使用的錯誤處理器,它能以一種優雅的方式處理由操作系統提供的數據的編碼問題。在解碼出錯時會將出錯字節存儲到一個很少被使用到的 Unicode 編碼范圍內。在編碼時將那些隱藏值又還原回原先解碼失敗的字節序列。它不僅對于 OS API 非常有用,也能很容易的處理其他情況下的編碼錯誤。
使用這個版本產生的輸出如下:
>>> for name in files: ... try: ... print(name) ... except UnicodeEncodeError: ... print(bad_filename(name)) ... spam.py b?d.txt foo.txt >>>這一小節主題可能會被大部分讀者所忽略。但是如果你在編寫依賴文件名和文件系統的關鍵任務程序時,就必須得考慮到這個。否則你可能會在某個周末被叫到辦公室去調試一些令人費解的錯誤。
總結
以上是生活随笔為你收集整理的《Python Cookbook 3rd》笔记(5.15):打印不合法的文件名的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法(5)-leetcode-explo
- 下一篇: 大数据学习(3)- 分布式文件系统HDF