csv --- CSV 檔案讀取及寫入

原始碼:Lib/csv.py


所謂的 CSV (Comma Separated Values) 檔案格式是試算表及資料庫中最常見的匯入、匯出檔案格式。在嘗試以 RFC 4180 中的標準化方式來描述格式之前,CSV 格式已經使用了許多年。由於缺少一個完善定義的標準,意味著各個不同的應用程式會在資料產生及銷毀時有微妙的差別。這些不同之處使得從不同資料來源處理 CSV 檔案時會非常擾人。儘管如此,雖然分隔符號和引號字元有所不同,整體的格式非常相似,可以寫個單一模組來高效率的操作這樣的資料,讓程式設計師可以隱藏讀取及寫入資料的細節。

csv 模組實作透過 class 去讀取、寫入 CSV 格式的表格資料。它讓程式設計師可以說出:「以 Excel 為首選並寫入該種格式的資料」或是「從 Excel 產生的檔案來讀取資料」,且無需知道這是 Excel 所使用的 CSV 格式等精確的細節。程式設計師也可以描述其他應用程式所理解的 CSV 格式或他們自行定義具有特殊意義的 CSV 格式。

csv 模組的 readerwriter 物件可以讀取及寫入序列。程式設計師也可以透過 DictReaderDictWriter class(類別)使用 dictionary (字典)讀取及寫入資料。

也參考

PEP 305 - CSV 檔案 API

Python Enhancement Proposal (PEP) 所提出的 Python 附加功能。

模組內容

csv 模組定義了以下函式:

csv.reader(csvfile, /, dialect='excel', **fmtparams)

回傳一個讀取器物件 (reader object) 並處理在指定的 csvfile 中的每一行,csvfile 必須是字串的可疊代物件 (iterable of strings),其中每個字串都要是讀取器所定義的 csv 格式,csvfile 通常是個類檔案物件或者 list。如果 csvfile 是個檔案物件,則需開啟時使用 newline=''[1] dialect 為一個可選填的參數,可以用為特定的 CSV dialect(方言) 定義一組參數。它可能為 Dialect 的一個子類別 (subclass) 的實例或是由 list_dialects() 函式回傳的多個字串中的其中之一。另一個可選填的關鍵字引數 fmtparams 可以在這個 dialect 中覆寫 (override) 個別的格式化參數 (formatting parameter)。關於 dialect 及格式化參數的完整說明,請見段落 Dialect 與格式參數

從 CSV 檔案讀取的每一列會回傳為一個字串列表。除非格式選項 QUOTE_NONNUMERIC 有被指定(在這個情況之下,沒有引號的欄位都會被轉換成浮點數),否則不會進行自動資料型別轉換。

一個簡短的用法範例:

>>> import csv
>>> with open('eggs.csv', newline='') as csvfile:
...     spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
...     for row in spamreader:
...         print(', '.join(row))
Spam, Spam, Spam, Spam, Spam, Baked Beans
Spam, Lovely Spam, Wonderful Spam
csv.writer(csvfile, /, dialect='excel', **fmtparams)

回傳一個寫入器物件 (writer object),其負責在給定的類檔案物件 (file-like object) 上將使用者的資料轉換為分隔字串 (delimited string)。csvfile 可以為具有 write() method 的任何物件。若 csvfile 為一個檔案物件,它應該使用 newline='' 開啟 [1]dialect 為一個可選填的參數,可以用為特定的 CSV dialect 定義一組參數。它可能為 Dialect 的一個子類別的實例或是由 list_dialects() 函式回傳的多個字串中的其中之一。另一個可選填的關鍵字引數 fmtparams 可以在這個 dialect 中覆寫個別的格式化參數。關於 dialect 及格式化參數的完整說明,請見段落 Dialect 與格式參數。為了更容易與有實作 DB API 的模組互相接合,None 值會被寫成空字串。雖然這不是一個可逆的變換,這使得dump (傾印) SQL NULL 資料值到 CSV 檔案上就無需讓 cursor.fetch* 呼叫回傳的資料進行預處理 (preprocessing)。其餘非字串的資料則會在寫入之前用 str() 函式進行字串化 (stringify)。

一個簡短的用法範例:

import csv
with open('eggs.csv', 'w', newline='') as csvfile:
    spamwriter = csv.writer(csvfile, delimiter=' ',
                            quotechar='|', quoting=csv.QUOTE_MINIMAL)
    spamwriter.writerow(['Spam'] * 5 + ['Baked Beans'])
    spamwriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])
csv.register_dialect(name, /, dialect='excel', **fmtparams)

dialectname 進行關聯 (associate)。name 必須為字串。這個 dialect 可以透過傳遞 Dialect 的子類別進行指定;或是關鍵字引數 fmtparams;或是以上兩者皆是,並透過關鍵字引數來覆寫 dialect 的參數。關於 dialect 及格式化參數的完整說明,請見段落 Dialect 與格式參數

csv.unregister_dialect(name)

從 dialect 註冊表 (registry) 中,刪除與 name 關聯的 dialect。若 name 如果不是註冊的 dialect 名稱,則會產生一個 Error

csv.get_dialect(name)

回傳一個與 name 關聯的 dialect。若 name 如果不是註冊的 dialect 名稱,則會產生一個 Error。這個函式會回傳一個 immutable (不可變物件) Dialect

csv.list_dialects()

回傳所有已註冊的 dialect 名稱。

csv.field_size_limit()
csv.field_size_limit(new_limit)

回傳目前的剖析器 (parser) 允許的最大字串大小。如果 new_limit 被給定,則會變成新的最大字串大小。

csv 模組定義了下列的類別:

class csv.DictReader(f, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds)

建立一個物件,其運作上就像一般的讀取器,但可以將每一列資訊 map (對映) 到 dict 中,可以透過選填的參數 fieldnames 設定 key。

參數 fieldnames 是一個 sequence。如果 fieldnames 被省略了,檔案 f 中第一列的值會被當作欄位標題,且於結果中會被省略。如果 fieldname 有提供,它們就會被使用,且第一列會被包含在結果中。不管欄位標題是如何決定的,dictionary 都會保留原始的排序。

如果一列資料中的欄位比欄位標題還多,其餘的資料及以 restkey (預設為 None)特指的欄位標題會放入列表當中並儲存。如果一個非空的 (non-blank) 列中的欄位比欄位標題還少,缺少的值則會填入 restval (預設為 None)的值。

所有其他選填的引數或關鍵字引數皆會傳遞至下層的 reader 實例。

如果傳遞至 fieldnames 的引數是個疊代器,則會被迫成為一個 list

在 3.6 版的變更: 回傳的列已成為型別 OrderedDict

在 3.8 版的變更: 回傳的列已成為型別 dict

一個簡短的用法範例:

>>> import csv
>>> with open('names.csv', newline='') as csvfile:
...     reader = csv.DictReader(csvfile)
...     for row in reader:
...         print(row['first_name'], row['last_name'])
...
Eric Idle
John Cleese

>>> print(row)
{'first_name': 'John', 'last_name': 'Cleese'}
class csv.DictWriter(f, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwds)

建立一個物件,其運作上就像一般的寫入器,但可以將 dictionary map 到輸出的列上。參數 fieldnames 是一個鍵值的 sequence 且可以辨識 dictionary 中傳遞至 writerow() method 寫入至檔案 f 中的值。如果 dictionary 中缺少了 fieldnames 的鍵值,則會寫入選填的參數 restval 的值。如果傳遞至 writerow() method 的 dictionary 包含了一個 fieldnames 中不存在的鍵值,選填的參數 extrasaction 可以指出該執行的動作。如果它被設定為 'raise',預設會觸發 ValueError。如果它被設定為 'ignore',dictionary 中額外的值會被忽略。其他選填的引數或關鍵字引數皆會傳遞至下層的 writer 實例。

請記得這不像類別 DictReader,在類別 DictWriter 中,參數 fieldnames 並不是選填的。

如果傳遞至 fieldnames 的引數是個疊代器,則會被迫成為一個 list

一個簡短的用法範例:

import csv

with open('names.csv', 'w', newline='') as csvfile:
    fieldnames = ['first_name', 'last_name']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

    writer.writeheader()
    writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'})
    writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'})
    writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'})
class csv.Dialect

類別