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

類似的,為了寫入一個文本文件,使用帶有 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ù)。

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

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

Python支持非常多的文本編碼。幾個常見的編碼是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字符的直接映射。當讀取一個未知編碼的文本時使用latin-1編碼永遠不會產(chǎn)生解碼錯誤。使用latin-1編碼讀取一個文件的時候也許不能產(chǎn)生完全正確的文本解碼數(shù)據(jù),但是它也能從中提取出足夠多的有用數(shù)據(jù)。同時,如果你之后將數(shù)據(jù)回寫回去,原先的數(shù)據(jù)還是會保留的。

討論

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

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

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

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

為了說明兩者之間的差異,下面我在Unix機器上面讀取一個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'
>>>

最后一個問題就是文本文件中可能出現(xià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)
>>>

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

>>> # 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ù)來處理編碼錯誤,可能會讓你的生活變得很糟糕。對于文本處理的首要原則是確保你總是使用的是正確編碼。當模棱兩可的時候,就使用默認的設(shè)置(通常都是UTF-8)。

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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號