csv — CSV 檔案讀取和寫入

原始碼: Lib/csv.py


所謂的 CSV(逗號分隔值)格式是電子表格和資料庫最常用的匯入和匯出格式。在 RFC 4180 中嘗試以標準化方式描述該格式之前,CSV 格式已經使用了多年。缺乏明確的標準意味著不同應用程式生成和使用的資料中經常存在細微的差異。這些差異使得處理來自多個來源的 CSV 檔案很麻煩。儘管分隔符和引號字元各不相同,但總體格式足夠相似,因此可以編寫一個可以高效操作此類資料的單個模組,從而向程式設計師隱藏讀取和寫入資料的細節。

csv 模組實現了以 CSV 格式讀取和寫入表格資料的類。它允許程式設計師說“以 Excel 首選的格式寫入此資料”或“從 Excel 生成的此檔案中讀取資料”,而無需知道 Excel 使用的 CSV 格式的精確細節。程式設計師還可以描述其他應用程式理解的 CSV 格式或定義他們自己的專用 CSV 格式。

csv 模組的 readerwriter 物件讀取和寫入序列。程式設計師還可以使用 DictReaderDictWriter 類以字典形式讀取和寫入資料。

另請參閱

PEP 305 - CSV 檔案 API

提議將此新增到 Python 的 Python 增強提案。

模組內容

csv 模組定義了以下函式

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

返回一個 reader 物件,該物件將處理給定 csvfile 中的行。 csvfile 必須是字串的可迭代物件,每個字串都採用 reader 定義的 csv 格式。 csvfile 通常是類檔案物件或列表。如果 csvfile 是檔案物件,則應使用 newline='' 開啟。[1] 可以提供可選的 dialect 引數,該引數用於定義特定於特定 CSV 方言的一組引數。它可以是 Dialect 類的子類的例項,也可以是 list_dialects() 函式返回的字串之一。可以提供其他可選的 fmtparams 關鍵字引數來覆蓋當前方言中的各個格式化引數。有關方言和格式化引數的完整詳細資訊,請參閱 方言和格式化引數 部分。

從 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 物件,該物件負責將使用者的資料轉換為給定類檔案物件上的分隔字串。 csvfile 可以是任何具有 write() 方法的物件。如果 csvfile 是檔案物件,則應使用 newline='' 開啟[1]。可以提供可選的 dialect 引數,該引數用於定義特定於特定 CSV 方言的一組引數。它可以是 Dialect 類的子類的例項,也可以是 list_dialects() 函式返回的字串之一。可以提供其他可選的 fmtparams 關鍵字引數來覆蓋當前方言中的各個格式化引數。有關方言和格式化引數的完整詳細資訊,請參閱 方言和格式化引數 部分。為了儘可能方便地與實現 DB API 的模組進行互動,值 None 被寫入為空字串。雖然這不是可逆的轉換,但這使得將 SQL NULL 資料值轉儲到 CSV 檔案中更容易,而無需預處理從 cursor.fetch* 呼叫返回的資料。所有其他非字串資料在寫入之前都會使用 str() 進行字串化。

一個簡短的用法示例

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[, **fmtparams]])

dialectname 關聯。 name 必須是字串。可以透過傳遞 Dialect 的子類、或透過 fmtparams 關鍵字引數,或兩者都指定方言,其中關鍵字引數會覆蓋方言的引數。有關方言和格式化引數的完整詳細資訊,請參閱 方言和格式化引數 部分。

csv.unregister_dialect(name)

從方言登錄檔中刪除與 name 關聯的方言。如果 name 不是註冊的方言名稱,則會引發 Error

csv.get_dialect(name)

返回與name關聯的方言。如果 name 不是已註冊的方言名稱,則會引發 Error 異常。此函式返回一個不可變的 Dialect

csv.list_dialects()

返回所有已註冊方言的名稱。

csv.field_size_limit([new_limit])

返回解析器允許的當前最大欄位大小。如果給定 new_limit,則此值將成為新的限制。

csv 模組定義了以下類

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

建立一個行為類似於常規讀取器的物件,但將每行中的資訊對映到一個 dict,其鍵由可選的 fieldnames 引數給出。

fieldnames 引數是一個 序列。如果省略 fieldnames,則檔案 f 的第一行的值將用作欄位名,並且將從結果中省略。如果提供了 fieldnames,則將使用它們,並且第一行將包含在結果中。無論如何確定欄位名,字典都會保留其原始順序。

如果某行的欄位數多於欄位名,則剩餘資料將放入列表中,並使用 restkey 指定的欄位名儲存(預設為 None)。如果非空白行的欄位數少於欄位名,則缺失的值將用 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)

建立一個行為類似於常規寫入器的物件,但將字典對映到輸出行。fieldnames 引數是一個 sequence 的鍵,用於標識傳遞給 writerow() 方法的字典中值的寫入檔案 f 的順序。可選的 restval 引數指定如果字典在 fieldnames 中缺少鍵要寫入的值。如果傳遞給 writerow() 方法的字典包含在 fieldnames 中找不到的鍵,則可選的 extrasaction 引數指示要採取的操作。如果設定為 'raise'(預設值),則會引發 ValueError 異常。如果設定為 'ignore',則會忽略字典中的額外值。任何其他可選或關鍵字引數都將傳遞給底層的 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

Dialect 類是一個容器類,其屬性包含有關如何處理雙引號、空格、分隔符等的資訊。由於缺乏嚴格的 CSV 規範,不同的應用程式會產生略有不同的 CSV 資料。Dialect 例項定義了 readerwriter 例項的行為方式。

所有可用的 Dialect 名稱都由 list_dialects() 返回,並且可以透過其初始化器 (__init__) 函式將其註冊到特定的 readerwriter 類,如下所示

import csv

with open('students.csv', 'w', newline='') as csvfile:
    writer = csv.writer(csvfile, dialect='unix')
class csv.excel

excel 類定義了 Excel 生成的 CSV 檔案的常用屬性。它以方言名稱 'excel' 註冊。

class csv.excel_tab

excel_tab 類定義了 Excel 生成的製表符分隔檔案的常用屬性。它以方言名稱 'excel-tab' 註冊。

class csv.unix_dialect

unix_dialect 類定義了在 UNIX 系統上生成的 CSV 檔案的常用屬性,即使用 '\n' 作為行終止符並引用所有欄位。它使用方言名稱 'unix' 註冊。

在 3.2 版本中新增。

class csv.Sniffer

Sniffer 類用於推斷 CSV 檔案的格式。

Sniffer 類提供了兩個方法

sniff(sample, delimiters=None)

分析給定的sample並返回一個反映所找到引數的 Dialect 子類。如果給定了可選的delimiters引數,則將其解釋為包含可能有效的分隔符字元的字串。

has_header(sample)

分析樣本文字(假定為 CSV 格式)並返回 True 如果第一行看起來是一系列列標題。檢查每一列,將考慮以下兩個關鍵標準之一來估計樣本是否包含標題

  • 第二行到第 n 行包含數值

  • 第二行到第 n 行包含字串,其中至少有一個值的長度與該列的推定標題的長度不同。

取樣第一行之後的二十行;如果超過一半的列 + 行滿足條件,則返回 True

注意

此方法是一種粗略的啟發式方法,可能會產生誤報和漏報。

關於 Sniffer 用法的示例

with open('example.csv', newline='') as csvfile:
    dialect = csv.Sniffer().sniff(csvfile.read(1024))
    csvfile.seek(0)
    reader = csv.reader(csvfile, dialect)
    # ... process CSV file contents here ...

csv 模組定義了以下常量

csv.QUOTE_ALL

指示 writer 物件引用所有欄位。

csv.QUOTE_MINIMAL

指示 writer 物件僅引用包含特殊字元(如delimiterquotecharlineterminator 中的任何字元)的欄位。

csv.QUOTE_NONNUMERIC

指示 writer 物件引用所有非數值欄位。

指示 reader 物件將所有未引用的欄位轉換為 float 型別。

csv.QUOTE_NONE

指示 writer 物件永不引用欄位。噹噹前 delimiter 出現在輸出資料中時,它前面會加上當前 escapechar 字元。如果未設定 escapechar,則如果遇到任何需要轉義的字元,寫入器將引發 Error

指示 reader 物件不對引號字元執行任何特殊處理。

csv.QUOTE_NOTNULL

指示 writer 物件引用所有不是 None 的欄位。這與 QUOTE_ALL 類似,只是如果欄位值為 None,則會寫入一個空(未引用)的字串。

指示 reader 物件將空(未引用)的欄位解釋為 None,否則其行為與 QUOTE_ALL 相同。

在 3.12 版本中新增。

csv.QUOTE_STRINGS

指示 writer 物件始終在字串欄位周圍放置引號。這與 QUOTE_NONNUMERIC 類似,只是如果欄位值為 None,則會寫入一個空(未引用)的字串。

指示 reader 物件將空(未引用)的字串解釋為 None,否則其行為與 QUOTE_NONNUMERIC 相同。

在 3.12 版本中新增。

csv 模組定義了以下異常

exception csv.Error

當檢測到錯誤時,任何函式都會引發此異常。

方言和格式化引數

為了更容易指定輸入和輸出記錄的格式,特定的格式化引數被分組到方言中。方言是 Dialect 類的子類,其中包含描述 CSV 檔案格式的各種屬性。建立 readerwriter 物件時,程式設計師可以指定一個字串或 Dialect 類的子類作為方言引數。除了或代替 dialect 引數,程式設計師還可以指定單個格式化引數,這些引數的名稱與下面為 Dialect 類定義的屬性相同。

方言支援以下屬性

Dialect.delimiter

用於分隔欄位的單字元字串。它預設為 ','

Dialect.doublequote

控制如何引用出現在欄位內的 quotechar 例項。當 True 時,該字元會加倍。當 False 時,escapechar 用作 quotechar 的字首。它預設為 True

在輸出時,如果 doublequoteFalse 並且未設定 escapechar,則如果在欄位中找到 quotechar,將引發 Error

Dialect.escapechar

一個單字元字串,當quoting設定為QUOTE_NONE,且當doublequoteFalse時,由寫入器用於轉義delimiterquotechar。 在讀取時,escapechar 會刪除後續字元的任何特殊含義。 它預設為 None,表示停用轉義。

3.11 版本已更改: 不允許使用空的 escapechar

Dialect.lineterminator

用於終止 writer 生成的行的字串。 它預設為 '\r\n'

注意

reader 被硬編碼為識別 '\r''\n' 作為行尾,並忽略 lineterminator。 此行為在未來可能會更改。

Dialect.quotechar

用於引用包含特殊字元(例如 delimiterquotechar)或包含換行符的欄位的單字元字串。 它預設為 '"'

3.11 版本已更改: 不允許使用空的 quotechar

Dialect.quoting

控制寫入器何時生成引號以及讀取器何時識別引號。 它可以採用任何 QUOTE_* 常量,並預設為 QUOTE_MINIMAL

Dialect.skipinitialspace

當為 True 時,忽略緊跟在 delimiter 後的空格。 預設為 False

Dialect.strict

當為 True 時,在 CSV 輸入錯誤時引發異常 Error。 預設為 False

讀取器物件

讀取器物件(DictReader 例項和 reader() 函式返回的物件)具有以下公共方法

csvreader.__next__()

以列表形式(如果物件是從 reader() 返回的)或字典形式(如果它是 DictReader 例項)返回讀取器的可迭代物件的下一行,並根據當前的 Dialect 進行解析。 通常你應該將其作為 next(reader) 呼叫。

讀取器物件具有以下公共屬性

csvreader.dialect

一個對解析器使用的方言的只讀描述。

csvreader.line_num

從源迭代器讀取的行數。 這與返回的記錄數不同,因為記錄可以跨越多行。

DictReader 物件具有以下公共屬性

DictReader.fieldnames

如果未在建立物件時作為引數傳遞,則此屬性將在首次訪問或從檔案中讀取第一條記錄時初始化。

寫入器物件

writer 物件(DictWriter 例項和 writer() 函式返回的物件)具有以下公共方法。 對於 writer 物件,row 必須是字串或數字的可迭代物件,對於 DictWriter 物件,row 必須是將欄位名稱對映到字串或數字的字典(首先透過 str() 傳遞它們)。 請注意,複數會用括號括起來寫入。 這可能會給其他讀取 CSV 檔案的程式帶來一些問題(假設它們完全支援複數)。

csvwriter.writerow(row)

根據當前的 Dialectrow 引數寫入寫入器的檔案物件。 返回對底層檔案物件的 write 方法的呼叫返回值。

3.5 版本已更改: 添加了對任意可迭代物件的支援。

csvwriter.writerows(rows)

根據當前方言將 rows 中的所有元素(一個如上所述的 row 物件的可迭代物件)寫入寫入器的檔案物件。

寫入器物件具有以下公共屬性

csvwriter.dialect

一個對寫入器使用的方言的只讀描述。

DictWriter 物件具有以下公共方法

DictWriter.writeheader()

將包含欄位名稱(如建構函式中指定)的行寫入寫入器的檔案物件,並根據當前的方言進行格式化。 返回內部使用的 csvwriter.writerow() 呼叫的返回值。

在 3.2 版本中新增。

3.8 版本已更改: writeheader() 現在還返回其內部使用的 csvwriter.writerow() 方法的返回值。

示例

讀取 CSV 檔案的最簡單示例

import csv
with open('some.csv', newline='') as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

讀取具有替代格式的檔案

import csv
with open('passwd', newline='') as f:
    reader = csv.reader(f, delimiter=':', quoting=csv.QUOTE_NONE)
    for row in reader:
        print(row)

相應的最簡單的寫入示例是

import csv
with open('some.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerows(someiterable)

由於 open() 用於開啟 CSV 檔案進行讀取,該檔案預設會使用系統預設編碼(請參閱 locale.getencoding())解碼為 unicode。 要使用不同的編碼解碼檔案,請使用 open 的 encoding 引數

import csv
with open('some.csv', newline='', encoding='utf-8') as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

這同樣適用於使用系統預設編碼以外的編碼寫入:在開啟輸出檔案時指定 encoding 引數。

註冊新的方言

import csv
csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)
with open('passwd', newline='') as f:
    reader = csv.reader(f, 'unixpwd')

稍微高階一點的讀取器用法——捕獲和報告錯誤

import csv, sys
filename = 'some.csv'
with open(filename, newline='') as f:
    reader = csv.reader(f)
    try:
        for row in reader:
            print(row)
    except csv.Error as e:
        sys.exit('file {}, line {}: {}'.format(filename, reader.line_num, e))

雖然該模組不直接支援解析字串,但可以很容易地完成

import csv
for row in csv.reader(['one,two,three']):
    print(row)

腳註