1. 程式人生 > >python I/O+編碼 小例

python I/O+編碼 小例

 

python3使用Unicode編碼

 

str = ord('中') #ord獲取字元整數表示 這個整數表示也就是Unicode編碼去對映的 也就是'中'字在記憶體中真正表示的值
print(str)

#在記憶體中以Unicode表示,一個字元對應若干個位元組。如果要在網路上傳輸,或者儲存到磁碟上,就需要把str變為以位元組為單位的bytes
str = '中文'.encode('utf-8') #把Unicode字串編碼成utf-8的bytes
print(str)

#decode把utf-8編碼的bytes解碼成Unicode字串
str = b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8') #'中文'的utf-8編碼的bytes
print(str)

output:

20013
b'\xe4\xb8\xad\xe6\x96\x87'
中文

配合編碼進行I/0:

with open('msg.txt', 'wb') as file:
        s = '中文'.encode('UTF-8')
        file.write(s)                   #二進位制開啟檔案 必須寫入bytes 位元組陣列型別,並且不能指定encoding

with open('msg.txt', 'w', encoding='UTF-8') as file:
    s = '中文'                        #字元形式開啟檔案 寫入的就直接是str型別 按照給定的encoding去寫
    file.write(s)

 可以看到,如果以二進位制形式開啟檔案,那麼就需要用到上面所說的encode和decode。

這個擴充套件到讀檔案,還有網路流讀寫都是一樣的。理解了最簡單的例子,才能往復雜的去寫,不然越寫越糊塗。

再來看個例子,在記憶體中讀寫,原理是一模一樣的,不過資料交換從記憶體和硬碟變成了記憶體和記憶體:

from io import StringIO

with StringIO() as s:
    s.write('hello')
    s.write(' ')
    s.write('world!')            #seek已經定位到11 讀寫都會改變seek 就像檔案裡的遊標一樣

    print(s.getvalue())   

with StringIO('''你好           
世界!''') as s:                 #如果想重新讀上面寫好的StringIO 那麼用seek(0)重新定位即可
    ls = s.readlines()
    for l in ls:
        print(l,end='')

Output:
hello world!
你好
世界!

一樣的字元流,為什麼這裡字元流不需要指定編碼?其實之前我有篇部落格你真的明白Java和Python3使用Unicode編碼的含義嗎?已經詳細解釋過了,這個是因為python在記憶體中就是使用的Unicode編碼,我們沒法去改變,而檔案是儲存在硬碟上的,可以有多種編碼方式,所以當指定字元流寫入的時候,可以新增encoding欄位來指定檔案的編碼方式。

當然,如果你執意如此,你可以把字串decode,然後再轉回字串,就像下面這樣,不過,何必呢?

from io import StringIO

with StringIO() as s:
    a = str('中國'.encode('UTF-8'))
    s.write(a)

    print(s.getvalue())


Output:
b'\xe4\xb8\xad\xe5\x9b\xbd'

其實當你要這樣用的時候,需要選擇位元組流BytesIO

from io import BytesIO

with BytesIO() as b:
    b.write('中國'.encode('UTF-8'))
    print(b.getvalue())

with BytesIO(b'\xe4\xb8\x87\xe5\xb2\x81') as b:
    ls = b.readlines()
    for l in ls:
        print(l.decode(), end='')

Output:
b'\xe4\xb8\xad\xe5\x9b\xbd'
萬歲

可以看到,當改變通訊介質之後,python提供的介面是通用的,唯一不同的就是介質變了。