cook book:檔案與IO+資料編碼和處理
阿新 • • 發佈:2021-08-06
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:讀寫位元組資料 讀寫二進位制檔案,比如圖片,聲音檔案等, 使用rb
或wb
的open()
函式來讀取或寫入二進位制資料
# 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())