python字符集分析,解決windows下FTPClient下載中文名稱文件亂碼

    python中的中文編碼一直以來都是一個極爲頭大的問題,經常拋出編碼轉換的異常,python中的str和unicode到底是一個什麼東西呢?在python中提到unicode,一般指的是unicode對象,例如'哈哈'的unicode對象爲u'\u54c8\u54c8',而str,是一個字節數組,這個字節數組表示的是對unicode對象編碼(可以是utf-8、gbk、cp936、GB2312)後的存儲的格式。這裏它僅僅是一個字節流,沒有其它的含義,如果你想使這個字節流顯示的內容有意義,就必須用正確的編碼格式,解碼顯示

例如: 

>>> A = u"你好"
>>> A_UTF8 = A.encode("utf-8")
>>> print A_UTF8
浣犲ソ
>>> A_GBK = A.encode("gbk")
>>> print A_GBK
你好
>>> A_UTF8
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> A_GBK
'\xc4\xe3\xba\xc3'

    對於unicode對象"你好"進行編碼,編碼成一個utf-8編碼,A_UTF8就是是一個字節數組,存放的就是'\xe4\xbd\xa0\xe5\xa5\xbd',但是這僅僅是一個字節數組,不能通過print語句輸出成你好.因爲print語句它的實現是將要輸出的內容傳送了操作系統,操作系統會根據系統的編碼對輸入的字節流進行編碼,這就解釋了爲什麼utf-8格式的字符串"你好",輸出的是"浣犲ソ",因爲 '\xe4\xbd\xa0\xe5\xa5\xbd'用GB2312去解釋,其顯示的出來就是"浣犲ソ"。str記錄的是字節數組,只是某種編碼的存儲格式,至於輸出到文件或是打印出來是什麼格式,完全取決於其解碼的編碼將它解碼成什麼樣子。這裏再對print進行一點補充說明:當將一個unicode對象傳給print時,在內部會將該unicode對象進行一次轉換,轉換成本地的默認編碼(可能是這樣子的)


decode和encode

    字符串在Python內部的表示是unicode編碼,在做編碼轉換時,通常需要以unicode作爲中間編碼,即先將其他編碼的字符串解碼(decode)成unicode,再從unicode編碼(encode)成另一種編碼。            例:str1.decode('gb2312'),表示將gb2312編碼的字符串str1轉換成unicode

    str2.encode('gb2312'),表示將unicode編碼的字符串str2轉換成gb2312編碼。

    轉碼的時候一定要先搞明白,字符串str是什麼編碼,然後decode成unicode,然後再encode成其他編碼,在utf8的文件中,該字符串就是utf8編碼,如果是在gbk的文件中,則其編碼爲gbk。這種情況下,要進行編碼轉換,都需 要先用decode方法將其轉換成unicode編碼,再使用encode方法將其轉換成其他編碼。通常,在沒有指定特定的編碼方式時,都是使用的系統默認編碼創建的代碼文件。

    如果一個字符串已經是unicode了,再進行解碼則將出錯,因此通常要對其編碼方式是否爲unicode進行判斷:
    isinstance(s, unicode) #用來判斷是否爲unicode


例子:解決windows下python FTPClient下載中文文件名出錯的問題

def downloadfile():
    remotepath = os.path.join(remotepath, Zname).encode('utf-8')
    localpath = CreatDir()
    localpath = os.path.join(localpath, Zname).encode("gbk")
    print "開始連接FTP服務器..."
    ftp = ftpconnect()
    ftp.set_debuglevel(2) #打開調試
    #print ftp.getwelcome() #顯示ftp服務器歡迎信息
    bufsize = 1024 #設置緩衝塊大小
    try:
        print "開始接收服務器上的文件..."
        fp = open(localpath.decode('gbk'), 'wb') #以寫模式在本地打開文件
        ftp.retrbinary('RETR ' + remotepath,fp.write,bufsize) #接收服務器上文件並寫入本地文件
        logging.debug("讀取遠程地址爲%s" % remotepath.decode("utf8").encode("gbk"))
        logging.debug("%s下載成功路徑爲: %s" %(Zname, localpath))
        print "%s下載成功路徑爲: %s" %(Zname, localpath)
        fp.close()
    except Exception, e:
        print e
        logging.debug("%s下載失敗關閉文件,退出FTP服務器" %Zname)
        print "下載失敗"
        os.remove(localpath)
    finally:
        ftp.quit() #退出ftp服務器



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章