1. 程式人生 > 其它 >cook book:檔案與IO+資料編碼和處理

cook book:檔案與IO+資料編碼和處理

1:讀寫文字資料 :讀寫各種不同編碼的文字資料ASCII,UTF-8或UTF-16編碼等

# rt模式下,python在讀取文字時會自動把\r\n轉換成\n,文字檔案用二進位制讀取用‘rt’;
# 使用帶有 rt 模式的 open() 函式讀取文字檔案
with open('aaaa', "rt") as f:
    data = f.read()
    print(data, type(data))

輸出aaaa檔案讀取出來的資料,\r\n都轉換成\n,讀取出來的資料是字串str型別

with open('aaaa', "rt") as f:
    for line in f:
        
print(line)
# 寫入一個文字檔案,使用帶有 wt 模式的 open() 函式, 如果之前檔案內容存在則清除並覆蓋掉。
# 編寫文字資料塊
with open('somefile.txt', 'wt') as f:
    f.write(text1)
    f.write(text2)
    ...

# 重定向列印語句
with open('somefile.txt', 'wt') as f:
    print(line1, file=f)
    print(line2, file=f)
    ...
# 已存在檔案中新增內容,使用模式為 at 的 open() 函式。
# 檔案的讀寫操作預設使用系統編碼,可以通過呼叫 sys.getdefaultencoding() 來得到。 
# 在大多數機器上面都是utf-8編碼。如果你已經知道你要讀寫的文字是其他編碼方式,
那麼可以通過傳遞一個可選的 encoding 引數給open()函式
with open('somefile.txt', 'rt', encoding='latin-1') as f:
# Python支援非常多的文字編碼。幾個常見的編碼是ascii, latin-1, utf-8和utf-16。 
在web應用程式中通常都使用的是UTF-8。 ascii對應從U+0000到U+007F範圍內的7位字元。
latin-1是位元組0-255到U+0000至U+00FF範圍內Unicode字元的直接對映。
當讀取一個未知編碼的文字時使用latin-1編碼永遠不會產生解碼錯誤。
使用latin-1編碼讀取一個檔案的時候也許不能產生完全正確的文字解碼資料,
但是它也能從中提取出足夠多的有用資料。同時,如果你之後將資料回寫回去,原先的資料還是會保留的
# with語句
# with語句給被使用到的檔案建立了一個上下文環境, 但 with 控制塊結束時,檔案會自動關閉。你也可以不使用 with 語句,但是這時候你就必須記得手動關閉檔案
f = open('somefile.txt', 'rt')
data = f.read()
f.close()

# 換行符的識別Unix和Windows中是不一樣,分別是 \n 和 \r\n 
# 預設情況下,Python會以統一模式處理換行符。 這種模式下,在讀取文字的時候,
Python可以識別所有的普通換行符並將其轉換為單個 \n 字元。 類似的,在輸出時會將換行符 \n 轉換為系統預設的換行符。
如果你不希望這種預設的處理方式,可以給 open() 函式傳入引數 newline='' ,
with open('somefile.txt', 'rt', newline='') as f:
# 在Unix機器上面讀取一個Windows上面的文字檔案
    內容是 hello world!\r\n
>>> # 已啟用換行轉換(預設)
>>> f = open('hello.txt', 'rt')
>>> f.read()
'hello world!\n'

>>> # 新行翻譯已禁用
>>> g = open('hello.txt', 'rt', newline='')
>>> g.read()
'hello world!\r\n'
>>>
# 讀取檔案編碼錯誤問題,讀取或者寫入一個文字檔案時,你可能會遇到一個編碼或者解碼錯誤
>>> f = open('sample.txt', 'rt', encoding='ascii')
>>> f.read()
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "/usr/local/lib/python3.3/encodings/ascii.py", line 26, in decode
        return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position
12: ordinal not in range(128)
>>>

這種錯誤通常表示你讀取文字時指定的編碼不正確,

# 仔細閱讀說明並確認你的檔案編碼是正確的(比如使用UTF-8而不是Latin-1編碼或其他)。 
如果編碼錯誤還是存在的話,你可以給 open() 函式傳遞一個可選的 errors 引數來處理這些錯誤。 下面是一些處理常見錯誤的方法
>>> # 用Unicode U+fffd替換字元替換壞字元 >>> f = open('sample.txt', 'rt', encoding='ascii', errors='replace') >>> f.read() 'Spicy Jalape?o!' >>> # 完全忽略壞字元 >>> g = open('sample.txt', 'rt', encoding='ascii', errors='ignore') >>> g.read() 'Spicy Jalapeo!' >>> # 對於文字處理的首要原則是確保你總是使用的是正確編碼。當模稜兩可的時候,就使用預設的設定(通常都是UTF-8)

2:列印輸出至檔案中 將print()函式的輸出重定向到一個檔案中去 ——>在print()函式中指定file關鍵字引數

with open('d:/work/test.txt', 'wt') as f:
    print('Hello World!', file=f)
檔案必須是以文字模式開啟。 如果檔案是二進位制模式的話,列印就會出錯

3:使用其他分隔符或行終止符列印使用print()函式輸出資料,改變預設的分隔符或者行尾符

# print() 函式中使用 sep 和 end 關鍵字引數,改變輸出方式
print('ACME', 50, 91.5)                         # ACME 50 91.5
print('ACME', 50, 91.5, sep=',')                # ACME,50,91.5
print('ACME', 50, 91.5, sep=',', end='!!\n')    # ACME,50,91.5!!

# end 引數可以在輸出中禁止換行
for i in range(5):
    print(i, end=' ')

# str.join和sep最後輸出一樣
print(','.join(('ACME', '50', '91.5')))
print('ACME', 50, 91.5, sep=',')

# str.join() 的問題在於它僅僅適用於字串
row = ('ACME', 50, 91.5)
print(','.join(row))    #  報錯join裡面的引數需要每個都是字串
print(','.join(str(x) for x in row))   # 需要這樣寫

# 直接使用sep引數也可以
row = ('ACME', 50, 91.5)
print(*row, sep=',')

4:讀寫位元組資料 讀寫二進位制檔案,比如圖片,聲音檔案等, 使用rbwbopen()函式來讀取或寫入二進位制資料

# rb 或 wb 的 open() 函式來讀取或寫入二進位制資料
# 以單位元組字串的形式讀取整個檔案
with open('somefile.bin', 'rb') as f:
    data = f.read()

# 將二進位制資料寫入檔案
with open('somefile.bin', 'wb') as f:
    f.write(b'Hello World')

# 讀取二進位制資料時,需要指明的是所有返回的資料都是位元組字串格式的,而不是文字字串。 
# 在寫入的時候,必須保證引數是以位元組形式對外暴露資料的物件(比如位元組字串,位元組陣列物件等)
# 讀取二進位制資料的時候,位元組字串和文字字串的語義差異可能會導致一個潛在的陷阱,索引和迭代動作返回的是位元組的值而不是位元組字串
t = 'Hello World'
print(t[0])         # H

b = b'Hello World'
print(b[0])         # 72   返回的是位元組H的十進位制的值72,不是返回的b'H'這個位元組
        
# 從二進位制模式的檔案中讀取或寫入文字資料,必須確保要進行解碼和編碼操作
with open('somefile.bin', 'rb') as f:
    data = f.read(16)
    text = data.decode('utf-8')

with open('somefile.bin', 'wb') as f:
    text = 'Hello World'
    f.write(text.encode('utf-8'))

decode解碼,encode編碼
# 二進位制I/O還有一個鮮為人知的特性就是陣列和C結構體型別能直接被寫入,而不需要中間轉換為自己物件
import array
nums = array.array('i', [1, 2, 3, 4])
with open('data.bin','wb') as f:
    f.write(nums)
# 這個把陣列物件寫入文字,可以直接寫入這個陣列物件,並不是寫入一個字串
# 這個適用於任何實現了被稱之為”緩衝介面”的物件,這種物件會直接暴露其底層的記憶體緩衝區給能處理它的操作。 二進位制資料的寫入就是這類操作之一 # 很多物件還允許通過使用檔案物件的 readinto() 方法直接讀取二進位制資料到其底層的記憶體中去 >>> import array                      # array是陣列,這個數組裡面只能放數字 >>> a = array.array('i', [0, 0, 0, 0, 0, 0, 0, 0]) >>> with open('data.bin', 'rb') as f: ... f.readinto(a) # 從f檔案控制代碼中讀取資料後放到a這個容器中,所以返回[1, 2, 3, 4, 0, 0, 0, 0] ... 16 >>> a array('i', [1, 2, 3, 4, 0, 0, 0, 0]) >>>
# mmap,記憶體對映檔案,檔案data.bin可以放字串
import mmap

a = mmap.mmap(-1, 20)

with open('data.bin', 'rb') as f:
    f.readinto(a)
    print(a.read())