目錄html
標籤: 字符編碼 Pythonjava
本文主要記述做者如何經過Python腳本恢復跨平臺傳輸致使的目錄和文件名中文亂碼。做者對Python編程和字符編碼瞭解很少,紕漏不免,歡迎指正。同時,本文兼作學習筆記,存在囉嗦之處,敬請諒解。
本文同時也發佈於做業部落,閱讀體驗可能更好。python
一年前,做者將Windows XP系統主機下建立的一批文件(以多級目錄組織),經過Samba
手工拷貝至Linux系統主機,能正常顯示目錄和文件名中包含的中文字符。而後,經過filezilla
鏈接Linux主機,將上述文件下載至移動硬盤,這個過程當中也未出現亂碼。但將移動硬盤鏈接到Windows 7系統主機上時,卻發現目錄和文件名中包含的中文字符出現亂碼。linux
例如,文件名"GNU Readline庫函數的應用示例"和"守護進程接收終端輸入的一種變通性方法"分別顯示爲"GNU Readlineåºå½æ°çåºç¨ç¤ºä¾"和"å®æ¤è¿ç¨æ¥æ¶ç»ç«¯è¾å ¥çä¸ç§åéæ§æ¹æ³"。正則表達式
但除目錄和文件名出現中文亂碼外,文件內容並沒有亂碼。算法
做者當時並不熟悉字符編碼知識,因而請教《通俗易懂地解決中文亂碼問題(1) --- 跨平臺亂碼》一文的做者Roly-Poly。Roly-Poly很是熱心地轉換了上述兩個文件名,並給出效果圖:
以及相應的Java轉換方法:編程
String str = new String(new String(messyName.getBytes("ISO-8859-1"), "GBK").getBytes("GBK"), "UTF-8");
其中,messyName對應出現亂碼的字符串。getBytes(charset)
將Unicode編碼存儲的字符串按照charset編碼,並以字節數組表示;new String(bytes[], charset)
則將字節數組按照charset編碼進行組合識別,最後轉換爲Unicode存儲。所以,上述代碼表示先將當前編碼從 ISO-8859-1轉爲GBK,而後再從GBK轉爲UTF-8。windows
固然,Roly-Poly的轉換仍有缺憾,畢竟還存在未能正確解析的亂碼。"幸運"的是,當時出於謹慎,做者分別經過dir /S path
、tree /F path
(Windows)和ls -lRS --time-style=long-iso
(Linux)建立了三份文件列表。這樣,在Roly-Poly轉碼的基礎上再作些校驗,有望替換爲徹底正確的文件名。數組
然而,一方面由於做者對Java語言和字符編碼比較陌生(主要是懶),另外一方面由於解析文件列表並改名的工做量預期較大,做者一直未付諸實踐。直到最近,纔開始從頭着手處理亂碼問題。這一過程學到很多知識,也走過很多彎路。教訓就是:凡事要一氣呵成!xcode
做者使用Python 2.7
自帶的IDLE
進行編碼調試。除非特別說明,本文全部代碼均爲Python語言。
參考Python字符編碼詳解一文,獲取當前環境的默認編碼:
#!/usr/bin/python # -*- coding: utf-8 -*- import sys, locale def SysCoding(): fmt = '{0}:{1}' #當前系統所使用的默認字符編碼 print fmt.format('DefaultEncoding ', sys.getdefaultencoding()) #轉換Unicode文件名至系統文件名時所用的編碼('None'表示使用系統默認編碼) print fmt.format('FileSystemEncoding ', sys.getfilesystemencoding()) #默認的區域設置並返回元祖(語言, 編碼) print fmt.format('DefaultLocale ', locale.getdefaultlocale()) #用戶首選的文本數據編碼(猜想結果) print fmt.format('PreferredEncoding ', locale.getpreferredencoding()) if __name__ == '__main__': SysCoding()
做者的Windows XP系統主機上,區域和語言選項
->區域選項
->標準和格式
及高級
->非Unicode程序的語言
均設置爲"中文(中國)";Windows 7系統主機上,區域和語言
->格式
及管理
->非Unicode程序的語言
均設置爲"中文(簡體,中國)"。兩臺主機的SysCoding()
輸出相同,均顯示以下:
DefaultEncoding :ascii FileSystemEncoding :mbcs DefaultLocale :('zh_CN', 'cp936') PreferredEncoding :cp936
可以使用chardet
模塊detect()
函數檢測給定字符的編碼。該函數返回檢測到的編碼'encoding'
及其可信度'confidence'
。
安裝方法爲:命令提示符下執行C:\Python27\Scripts>easy_install.exe chardet
後,自動下載egg文件包。若未安裝成功(import提示"ImportError: No module named chardet"),可到C:\Python27\Lib\site-packages目錄解壓egg文件包,將其中的chardet
目錄(全部文件)拷貝到site-packages下面便可。
安裝成功後,按照如下方法檢測字符編碼:
#coding: gbk import chardet print chardet.detect('abc') #{'confidence': 1.0, 'encoding': 'ascii'} print chardet.detect('喊') #{'confidence': 0.73, 'encoding': 'windows-1252'} print chardet.detect('漢') #{'confidence': 0.99, 'encoding': 'TIS-620'} ##Thailand print chardet.detect('漢中華人民共和國') #{'confidence': 0.99, 'encoding': 'GB2312'} print '漢中華人民共和國', repr('漢中華人民共和國') #漢中華人民共和國 '\xba\xba\xd6\xd0\xbb\xaa\xc8\xcb\xc3\xf1\xb9\xb2\xba\xcd\xb9\xfa'
可見,當字符"樣本"過少時,chardet
檢測結果並不許確(如'漢'被識別爲泰文)。在Shell中執行上述檢測時,結果與之相同。
做爲對比,聲明爲coding: utf-8
時,檢測結果又是另外一番"景象":
import chardet print chardet.detect('abc') #{'confidence': 1.0, 'encoding': 'ascii'} print chardet.detect('æCUnitè¿è¡') #{'confidence': 0.99, 'encoding': 'utf-8'} print chardet.detect('喊') #{'confidence': 0.73, 'encoding': 'windows-1252'} print chardet.detect('漢') #{'confidence': 0.73, 'encoding': 'windows-1252'} print chardet.detect('漢中華人民共和國') #{'confidence': 0.99, 'encoding': 'utf-8'} print '漢中華人民共和國', repr('漢中華人民共和國') #奼変腑鍗庝漢姘戝叡鍜屽浗 '\xe6\xb1\x89\xe4\xb8\xad\xe5\x8d\x8e\xe4\xba\xba\xe6\xb0\x91\xe5\x85\xb1\xe5\x92\x8c\xe5\x9b\xbd'
可見,'å£è¯å¥æ_æ°æµ'
被檢測爲UTF-8編碼。這是由於UTF-8是ASCII的超集。當字符串序列中全部字符均爲ASCII符號(前128個字符)時,chardet
認爲該串爲ASCII編碼;當字符串序列中也含有全部擴展ASCII符號時,chardet
極可能認爲該串爲UTF-8編碼。此外,print
根據本地操做系統默認字符編碼(GBK),將'漢中華人民共和國'
打印爲奼変腑鍗庝漢姘戝叡鍜屽浗
。
經過正則表達式提取文件列表中的目錄大小、文件數目、文件名及其大小、建立時間等信息,再遍歷移動硬盤亂碼目錄,進行匹配和改名。爲保險起見,應維護一份映射文件,存儲文件路徑、原名和新名,以便恢復或校訂。
爲減小匹配和改名次數,只操做名稱包含字母數字之外字符的目錄和文件。此外,還可對文件列表排序,如dir path /S /O:S
(按大小升序排列)。
由於word、網頁等文件打開後一般能夠看到標題,做者得以整理若干文件亂碼名與正常名的映射數據。這樣,藉助機器學習(如基於實例的算法),最終有望消除全部亂碼。
顯然,這一方案難度過高,並不現實。
首先,建立名稱正常的多級目錄供調試用。之因此不用原始亂碼目錄調試,是由於一旦測試失敗極可能會破壞"樣本"。
而後,經過如下代碼獲取單級目錄的大小、文件數目、文件名及大小、建立時間等信息:
import time from os.path import join, getsize, getmtime, getctime CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) #os.getcwd()返回當前工做目錄 def FilesInfo(): for root, dirs, files in os.walk(CURRENT_DIR): for file in files: path = join(root, file) ctime = time.ctime(getctime(path)) #建立時間 print 'Name:%-12s Size:%-7s Ctime:%s' %(file, getsize(path), ctime) print root, "consumes", print sum(getsize(join(root, file)) for file in files), print "bytes in", len(files), "non-directory files!"
注意,當本模塊由其餘模塊import並執行時,os.getcwd()
返回的並不是本模塊目錄。
執行FilesInfo()
後,輸出結果以下:
Name:Coding.py Size:7936 Ctime:Mon Feb 29 09:41:15 2016 Name:d_res.bmp Size:522534 Ctime:Mon Feb 29 09:41:15 2016 Name:error3.bmp Size:70782 Ctime:Mon Feb 29 09:41:15 2016 Name:Open.bmp Size:354746 Ctime:Mon Feb 29 09:41:15 2016 Name:Thumbs.db Size:19968 Ctime:Mon Feb 29 09:41:47 2016 Name:typec.bmp Size:199022 Ctime:Mon Feb 29 09:41:15 2016 Name:WalkDir.py Size:4894 Ctime:Mon Feb 29 09:41:15 2016 Name:復Coding.py Size:6564 Ctime:Mon Feb 29 15:41:37 2016 E:\PyTest\stuff consumes 1186446 bytes in 8 non-directory files!
在命令提示符下dir \F
出調試目錄的結構。截取部分以下:
C:\Program Files\IDM Computer Solutions\UEStudio>e: E:\PyTest 的目錄 2016-02-24 11:53 <DIR> . 2016-02-24 11:53 <DIR> .. 2016-02-23 17:22 1,434 backup_ver2.py
而後,經過ParseFileList()
函數解析出"E:\PyTest"
之類的路徑:
import codecs, re def ParseFileList(): #Windows記事本默認的字符編碼爲"ANSI"(實際是GBK) file = codecs.open(r'E:\PyTest\filelist.txt', encoding='gbk') for line in file: #下句等效於m = re.match(u' (.+) 的目錄\s*$', line) m = re.compile(u""" # Python默認字符編碼爲Ansi, 需加u轉爲Unicode (.+) 的目錄 # 將' 的目錄'前的部分做爲分組(Group) \s*$ # 行尾""", re.X).match(line) if m != None: print m.groups()[0]
注意,此處並未使用內置的open()
方法打開文件。由於該方法獲得的line
爲str類型,須要使用正確的編碼格式進行decode(),不然將沒法匹配到"的目錄"
。而codecs.open()
方法打開文件時讀取的就是Unicode類型,不容易出現編碼問題。
固然,若將源代碼文件中的字符編碼聲明改成#coding=gbk
,並去掉pattern字符串前綴u
,則使用內置的open()
方法仍可匹配到"的目錄"
。
目錄大小、文件數目、文件名及其大小等,都可經過合適的正則表達式提取。然而,做者很快意識到,根據文件列表遍歷和改名的方案實現起來過於複雜。因而,放棄正則匹配的嘗試。
雖然文件列表正則匹配的方案不可行,但遍歷和改名倒是全部方案所必需的。
Python中有三種遍歷目錄的方法,即os.listdir()
、os.walk()
和os.path.walk()
。這三者中,做者首選os.walk()
方法,遍歷代碼以下:
import os def ValidateDir(dirPath): #判斷路徑是否爲Unicode。若否,將其轉換爲Unicode編碼 if isinstance(dirPath, unicode) == False: #下句等效於dirPath = dirPath.decode('utf8') dirPath = unicode(dirPath, 'utf8') #判斷路徑是否存在(不區分大小寫) if os.path.exists(dirPath) == False: print dirPath + ' is non-existent!' return '' #判斷路徑是否爲目錄(不區分大小寫) if os.path.isdir(dirPath) == False: print dirPath + ' is not a directory!' return '' return dirPath def WalkDirReport(dirPath, fileNum): print '##############' + str(fileNum) + ' files processed##############' def WalkDir(dirPath): dirPath = ValidateDir(dirPath) if not dirPath: return #遍歷路徑下的文件及子目錄 fileNum = 0 for root, dirs, files in os.walk(dirPath): for file in files: #處理文件 #ChangeNames(root, file) #RestoreNames(root, file) fileNum += 1 while(fileNum % 100) == 0: prompt = '$' + str(fileNum) + ' files processed, ' \ + '''pause for checking. Type 'c' to continue: ''' if raw_input(prompt) == 'c': break WalkDirReport(dirPath, fileNum)
其中,ValidateDir()
用於校驗路徑合法性,同時還將非Unicode路徑轉爲Unicode路徑(該步驟也可由使用者自行完成)。
os.listdir()
方法遍歷目錄則較爲"笨拙",對好比下:
def WalkDir_unsafe(dirPath): dirPath = ValidateDir(dirPath) if not dirPath: return #遍歷路徑下的文件及子目錄 fileNum = 0 nameList = os.listdir(dirPath) for name in nameList: path = os.path.join(dirPath, name) #類型爲目錄,遞歸(存在棧溢出風險) if os.path.isdir(path) == True: fileNum += WalkDir_unsafe(path) continue #處理文件 '''此時name等效於os.path.basename(path),即文件名; dirPath等效於os.path.dirname(path),即目錄名; path等效於os.path.abspath(os.path.basename(path)),即絕對路徑''' fileNum += 1 return fileNum
由於採用遞歸處理,因此該方法存在棧溢出風險(不過做者還沒有遇到這種狀況)。使用時,需按照以下方式調用:
WalkDirReport(r'E:\Pytest\測試', WalkDir_unsafe(r'E:\Pytest\測試'))
注意,雖然os.walk()
自己仍由os.listdir()
遞歸實現,但倒是生成器(generator)寫法,相比普通遞歸更節省內存資源。
遍歷目錄調試經過後,就可着手實現目錄和文件改名。爲簡單起見,改名規則爲"尾部添0",即"E:\a\b.txt"
會轉換爲"E:\a0\b.txt0"
。同時提供恢復函數,以便反覆調試。代碼以下:
def ChangeNames(dir, file): #將'E:\a\b.txt'轉換爲'E:\a0\b.txt0',以此類推 filePath = os.path.join(dir, file) newdir = dir.split('\\') newdir[1:] = map(lambda x: x+'0', newdir[1:]) #盤符不變 newdir = '\\'.join(newdir) ufilePath = os.path.join(newdir, file) + '0' print filePath + ' => ' + ufilePath os.renames(filePath, ufilePath) def RestoreNames(dir, file): #將'E:\a0\b.txt0'恢復爲'E:\a\b.txt',以此類推 filePath = os.path.join(dir, file) newdir = dir.split('\\') newdir[1:] = map(lambda x: x[:-1], newdir[1:]) newdir = '\\'.join(newdir) ufilePath = os.path.join(newdir, file)[:-1] print filePath + ' => ' + ufilePath os.renames(filePath, ufilePath)
可見,"添0"和恢復的方法比較"笨拙"。但做爲Python新手,做者暫時只能如此。結合遍歷代碼,ChangeNames()
和RestoreNames()
可有效地改名和恢復。
注意os.renames()
方法,該方法可對嵌套目錄及其文件改名,可能會建立臨時目錄以存放新命名的子目錄和文件。所以,若以WalkDir(r'E:\bPytest')
方式調用且bPytest
目錄下存在空的子目錄,則改名後該子目錄保持原名原位置(仍在E:\bPytest
目錄下),而其餘子目錄及文件被改名且"轉移"到E:\bPytest0
目錄下——同時出現bPytest
和bPytest0
兩個目錄!
遍歷和改名調試成功後,接下來即是重中之重——亂碼文件名恢復。
瀏覽各類網絡資料後,做者終於在Stackoverflow
網站上一則問答Getting correct utf8 Chinese characters from messed-up iso-8859-1 in Python and MySQL裏找到一線曙光。回答者經過u'最'.encode('cp1252').decode('utf8')
成功地將最
轉換爲"最"
——這與做者遇到的亂碼何其類似!
在嘗試cp1252
、cp1254
...等衆多Windows編碼後,做者終於找到正確的編碼格式,即latin_1
,別名iso-8859-1
, iso8859-1
, 8859
, cp819
, latin
, latin1
, L1
。測試代碼以下:
print u'项ç®ä¸éæCUnitè¿è¡å¼åæµè¯'.encode('latin_1').decode('utf8') print u'ãNBCå¤é´æ°é»(2011-2å£)'.encode('latin_1').decode('utf8') print 'æ°æµªå客'.decode('utf8').encode('latin_1').decode('utf8')
其中,u'string'
等效於'string'.decode('utf8')
。運行結果爲:
項目中集成CUnit進行開發測試 《NBC夜間新聞(2011-2季) 新浪博客
經人工檢驗,徹底符合指望!
此時再回想Roly-Poly提供的Java轉碼語句:
String str = new String(new String(messyName.getBytes("ISO-8859-1"), "GBK").getBytes("GBK"), "UTF-8");
由於字符串在Java內存中以Unicode編碼存儲,且getBytes()
和new String()
分別對應Python裏的encode()
和decode()
,因此等效的Python轉碼語句以下:
str = u'messyName'.encode('latin_1').decode('gbk').encode('gbk').decode('utf8')
從字符編碼規則可知,通過GBK編解碼"中轉"後,極可能出現data loss。以第一章的兩個文件名爲例,其Python轉碼以下:
s1 = u'GNU Readlineåºå½æ°çåºç¨ç¤ºä¾'.encode('latin_1').decode('gbk').encode('gbk','replace').decode('utf8') s2 = u'å®æ¤è¿ç¨æ¥æ¶ç»ç«¯è¾å ¥çä¸ç§åéæ§æ¹æ³'.encode('latin_1').decode('gbk','replace').encode('gbk','replace').decode('utf8','replace') s3 = u'å®æ¤è¿ç¨æ¥æ¶ç»ç«¯è¾å ¥çä¸ç§åéæ§æ¹æ³'.encode('latin_1').decode('utf8') print s1 #GNU Readline庫函數的應用示例 print s2 #守護進程接收終�?輸入的一種變通�?方法 print s3 #守護進程接收終端輸入的一種變通性方法
其中,'replace'
參數以適當的字符替換編解碼過程當中沒法識別的字符,不然將產生UnicodeDecodeError
和UnicodeEncodeError
異常。可見,就本文問題而言,並不須要GBK編解碼"中轉"。
文件名字符串亂碼恢復成功後,接下來將對文件改名。該步驟須要在掛接移動硬盤的Windows 7主機上進行,由於在Windows XP主機上文件名亂碼沒法以指望的方式顯示和解析。例如:
最後那個以亂碼字符串爲名建立的文件,沒法打開(UEStudio提示"含有一個無效的路徑",記事本提示"無效的窗口句柄"),os.rename()
也會報錯。
在Windows 7主機上,做者從移動硬盤拷貝一個單級亂碼目錄至磁盤做調試用。而後,編寫代碼恢復該目錄下的全部亂碼文件名:
from nt import chdir def RecodeName(dirPath): nameList = os.listdir(dirPath) for fileName in nameList: try: ufileName = fileName.encode('latin_1').decode('utf8') except UnicodeEncodeError as e: print '[e]' + fileName + '(Possibly needn\'t xcode!)' continue print (fileName + ' => ' + ufileName) #rename以前要先用chdir()函數進入到目標文件所在的路徑 chdir(dirPath) os.rename(fileName, ufileName)
由於存在某些文件已被手工改名的可能性,encode('latin_1')
時會拋出UnicodeEncodeError
異常,因此須要跳過這些文件。
運行結果以下:
8.26å京990å°ç»éªï¼å¸æ对以åç人æå¸®å© - è±è¯æä¸èè¯(TOEIC) - 大家论å -.url => 8.26南京990小經驗,但願對之後的人有幫助 - 英語託業考試(TOEIC) - 你們論壇 -.url ~2011.5.29~æä¸905ææ³~æ谢大家ç½è®ºå~å¸æè½ç»å¤§å®¶å¸¦æ¥å¸®å© - è±è¯æä¸èè¯(TOEIC) - 大家论å -.url => ~2011.5.29~託業905感想~感謝你們網論壇~但願能給你們帶來幫助 - 英語託業考試(TOEIC) - 你們論壇 -.url ä¸å½é æç½.url => 中國雅思網.url å¦ä½æé«è±è¯å¬å_æé«è±è¯å¬åçæ¹æ³_å¬å课å .url => 如何提升英語聽力_提升英語聽力的方法_聽力課堂.url >>>
經驗證,指定目錄下全部亂碼文件名均正確恢復。
單級目錄下文件名亂碼消除後,做者換用os.renames()
方法消除嵌套目錄名及其文件名。代碼以下:
def RecodeNames(dir, file): filePath = os.path.join(dir, file) try: filePathNew = filePath.encode('latin_1').decode('utf8') except UnicodeEncodeError as e: '''os.renames()會建立臨時目錄以存放新命名的子目錄和文件,故此處異常 代表最底層文件已解碼成功(多是手工處理),但其目錄路徑仍未解碼。 所以,需構造已解碼全路徑,以便renames將上述文件拷貝至新目錄。 ''' print '[e]' + filePath + '(Possibly needn\'t xcode!)' filePathNew = os.path.join(dir.encode('latin_1').decode('utf8'), file) print (filePath + ' => ' + filePathNew) os.renames(filePath, filePathNew)
以WalkDir(r'F:\Pytest\Study')
運行,結果以下:
F:\Pytest\Study\John_æ°æµªå客.url => F:\Pytest\Study\John_新浪博客.url [e]F:\Pytest\Study\ABR\~2011.5.29~託業905感想~感謝你們網論壇~但願能給你們帶來幫助 - 英語託業考試(TOEIC) - 你們論壇 -.url(Possibly needn't xcode!) F:\Pytest\Study\ABR\~2011.5.29~託業905感想~感謝你們網論壇~但願能給你們帶來幫助 - 英語託業考試(TOEIC) - 你們論壇 -.url => F:\Pytest\Study\ABR\~2011.5.29~託業905感想~感謝你們網論壇~但願能給你們帶來幫助 - 英語託業考試(TOEIC) - 你們論壇 -.url F:\Pytest\Study\å¾ è¯»\ãNBCå¤é´æ°é»(2011-2å£)ã(NBC Nightly News)([m4v]è±è¯å¬åä¸è½½ -å¦ä¹ èµæåº.url => F:\Pytest\Study\待讀\《NBC夜間新聞(2011-2季)》(NBC Nightly News)([m4v]英語聽力下載 -學習資料庫.url ##############3 files processed##############
可見,根目錄和子目錄及全部下屬文件均正確改名。
讀者可能已經注意到,上述根目錄路徑名均爲英文字符。假如該路徑包含已解碼的中文目錄名(多是手工處理)呢?例如將Study
目錄名改成外語學習
。顯然,encode('latin_1')時會觸發UnicodeEncodeError
異常。所以,編解碼時須要跳過這些中文目錄名:
def RecodeNames(dir, file): filePath = os.path.join(dir, file) #對路徑解碼 paths = filePath.split('\\') for i in range(len(paths)): try: paths[i] = paths[i].encode('latin_1').decode('utf8') except UnicodeEncodeError as e: #路徑可能出現已解碼的中文(多是手工處理),再也不重複解碼 continue filePathNew = '\\'.join(paths) print (filePath + ' => ' + filePathNew) os.renames(filePath, filePathNew)
什麼?假如目錄名包含部分亂碼部分中文字符?拜託,這種狀況不可能出現。
激動人心的時刻來到了!本節將正式處理移動硬盤中的原始亂碼目錄和文件名。基於以上調試結果,最終的亂碼恢復代碼以下:
failedNamesList = [] def RecordFailedNames(name): failedNamesList.append(name) import ctypes def RecodeNames(dir, file): filePath = os.path.join(dir, file) #對路徑解碼 paths = filePath.split('\\') for i in range(len(paths)): try: paths[i] = paths[i].encode('latin_1').decode('utf8') except UnicodeEncodeError as e: #路徑可能出現已解碼的中文(多是手工處理),再也不重複解碼 continue filePathNew = '\\'.join(paths) print (filePath + ' => ' + filePathNew) try: os.renames(filePath, filePathNew) except WindowsError as e: print "[e]WindowsError({0}): {1}".format(e.winerror, ctypes.FormatError(e.winerror)) RecordFailedNames(filePath) def WalkDirReport(dirPath, fileNum): print '##############' + str(fileNum) + ' files processed##############' print 'Failed files(%d):' %(len(failedNamesList)) for i in range(len(failedNamesList)): print ' ' + failedNamesList[i]
某些亂碼文件名過長(多爲.mht文件),os.renames()
時會觸發WindowsError[3]
異常,如:
事實上,在資源管理器裏打開這些文件時,會提示"源路徑過長":
上述代碼可有效地恢復原始亂碼目錄和文件名。當時的運行截圖以下:
以及
經初步檢驗,改名成功。此時可經過tree
命令生成生成目錄樹,與原先保存的文件列表對比。遺憾的是,二者樹狀列表順序不一樣,沒法直接對比。固然,若是夠閒,也能夠編程比照。
本文所述的亂碼恢復實踐實際上是種"摸着石頭過河(trial and error)"的過程。若是當初先研究字符編碼,而不是雙管齊下,應該會避免很多彎路。固然論及性價比,孰優孰劣,亦未可知。 最後,關於Python字符編碼基礎知識,做者將在後續文章中加以說明,同時澄清本文一些謬誤之處。臉皮薄,就不說"敬請期待"了~~