5.1 讀寫文本數(shù)據(jù)

2018-02-24 15:26 更新

問題

你需要讀寫各種不同編碼的文本數(shù)據(jù),比如ASCII,UTF-8或UTF-16編碼等。

解決方案

使用帶有 rt 模式的 open() 函數(shù)讀取文本文件。如下所示:

# Read the entire file as a single string
with open('somefile.txt', 'rt') as f:
    data = f.read()

# Iterate over the lines of the file
with open('somefile.txt', 'rt') as f:
    for line in f:
        # process line
        ...

類似的,為了寫入一個(gè)文本文件,使用帶有 wt 模式的 open() 函數(shù),如果之前文件內(nèi)容存在則清除并覆蓋掉。如下所示:

# Write chunks of text data
with open('somefile.txt', 'wt') as f:
    f.write(text1)
    f.write(text2)
    ...

# Redirected print statement
with open('somefile.txt', 'wt') as f:
    print(line1, file=f)
    print(line2, file=f)
    ...

如果是在已存在文件中添加內(nèi)容,使用模式為 atopen() 函數(shù)。

文件的讀寫操作默認(rèn)使用系統(tǒng)編碼,可以通過調(diào)用 sys.getdefaultencoding() 來得到。在大多數(shù)機(jī)器上面都是utf-8編碼。如果你已經(jīng)知道你要讀寫的文本是其他編碼方式,那么可以通過傳遞一個(gè)可選的 encoding 參數(shù)給open()函數(shù)。如下所示:

with open('somefile.txt', 'rt', encoding='latin-1') as f:
    ...

Python支持非常多的文本編碼。幾個(gè)常見的編碼是ascii, latin-1, utf-8和utf-16。在web應(yīng)用程序中通常都使用的是UTF-8。ascii對應(yīng)從U+0000到U+007F范圍內(nèi)的7位字符。latin-1是字節(jié)0-255到U+0000至U+00FF范圍內(nèi)Unicode字符的直接映射。當(dāng)讀取一個(gè)未知編碼的文本時(shí)使用latin-1編碼永遠(yuǎn)不會(huì)產(chǎn)生解碼錯(cuò)誤。使用latin-1編碼讀取一個(gè)文件的時(shí)候也許不能產(chǎn)生完全正確的文本解碼數(shù)據(jù),但是它也能從中提取出足夠多的有用數(shù)據(jù)。同時(shí),如果你之后將數(shù)據(jù)回寫回去,原先的數(shù)據(jù)還是會(huì)保留的。

討論

讀寫文本文件一般來講是比較簡單的。但是也幾點(diǎn)是需要注意的。首先,在例子程序中的with語句給被使用到的文件創(chuàng)建了一個(gè)上下文環(huán)境,但with控制塊結(jié)束時(shí),文件會(huì)自動(dòng)關(guān)閉。你也可以不使用with語句,但是這時(shí)候你就必須記得手動(dòng)關(guān)閉文件:

f = open('somefile.txt', 'rt')
data = f.read()
f.close()

另外一個(gè)問題是關(guān)于換行符的識(shí)別問題,在Unix和Windows中是不一樣的(分別是n和rn)。默認(rèn)情況下,Python會(huì)以統(tǒng)一模式處理換行符。這種模式下,在讀取文本的時(shí)候,Python可以識(shí)別所有的普通換行符并將其轉(zhuǎn)換為單個(gè) \n 字符。類似的,在輸出時(shí)會(huì)將換行符 \n 轉(zhuǎn)換為系統(tǒng)默認(rèn)的換行符。如果你不希望這種默認(rèn)的處理方式,可以給 open() 函數(shù)傳入?yún)?shù) newline='' ,就像下面這樣:

# Read with disabled newline translation
with open('somefile.txt', 'rt', newline='') as f:
    ...

為了說明兩者之間的差異,下面我在Unix機(jī)器上面讀取一個(gè)Windows上面的文本文件,里面的內(nèi)容是 hello world!\r\n

>>> # Newline translation enabled (the default)
>>> f = open('hello.txt', 'rt')
>>> f.read()
'hello world!\n'

>>> # Newline translation disabled
>>> g = open('hello.txt', 'rt', newline='')
>>> g.read()
'hello world!\r\n'
>>>

最后一個(gè)問題就是文本文件中可能出現(xiàn)的編碼錯(cuò)誤。但你讀取或者寫入一個(gè)文本文件時(shí),你可能會(huì)遇到一個(gè)編碼或者解碼錯(cuò)誤。比如:

>>> 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)
>>>

如果出現(xiàn)這個(gè)錯(cuò)誤,通常表示你讀取文本時(shí)指定的編碼不正確。你最好仔細(xì)閱讀說明并確認(rèn)你的文件編碼是正確的(比如使用UTF-8而不是Latin-1編碼或其他)。如果編碼錯(cuò)誤還是存在的話,你可以給 open() 函數(shù)傳遞一個(gè)可選的 errors 參數(shù)來處理這些錯(cuò)誤。下面是一些處理常見錯(cuò)誤的方法:

>>> # Replace bad chars with Unicode U+fffd replacement char
>>> f = open('sample.txt', 'rt', encoding='ascii', errors='replace')
>>> f.read()
'Spicy Jalape?o!'
>>> # Ignore bad chars entirely
>>> g = open('sample.txt', 'rt', encoding='ascii', errors='ignore')
>>> g.read()
'Spicy Jalapeo!'
>>>

如果你經(jīng)常使用 errors 參數(shù)來處理編碼錯(cuò)誤,可能會(huì)讓你的生活變得很糟糕。對于文本處理的首要原則是確保你總是使用的是正確編碼。當(dāng)模棱兩可的時(shí)候,就使用默認(rèn)的設(shè)置(通常都是UTF-8)。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)