csv --- CSV 文件讀寫?

源代碼: Lib/csv.py


CSV (Comma Separated Values) 格式是電子表格和數(shù)據(jù)庫中最常見的輸入、輸出文件格式。在 RFC 4180 規(guī)范推出的很多年前,CSV 格式就已經(jīng)被開始使用了,由于當(dāng)時并沒有合理的標(biāo)準(zhǔn),不同應(yīng)用程序讀寫的數(shù)據(jù)會存在細微的差別。這種差別讓處理多個來源的 CSV 文件變得困難。但盡管分隔符會變化,此類文件的大致格式是相似的,所以編寫一個單獨的模塊以高效處理此類數(shù)據(jù),將程序員從讀寫數(shù)據(jù)的繁瑣細節(jié)中解放出來是有可能的。

csv 模塊實現(xiàn)了 CSV 格式表單數(shù)據(jù)的讀寫。其提供了諸如“以兼容 Excel 的方式輸出數(shù)據(jù)文件”或“讀取 Excel 程序輸出的數(shù)據(jù)文件”的功能,程序員無需知道 Excel 所采用 CSV 格式的細節(jié)。此模塊同樣可以用于定義其他應(yīng)用程序可用的 CSV 格式或定義特定需求的 CSV 格式。

csv 模塊中的 reader 類和 writer 類可用于讀寫序列化的數(shù)據(jù)。也可使用 DictReader 類和 DictWriter 類以字典的形式讀寫數(shù)據(jù)。

參見

該實現(xiàn)在“Python 增強提議” - PEP 305 (CSV 文件 API) 中被提出

《Python 增強提議》提出了對 Python 的這一補充。

模塊內(nèi)容?

csv 模塊定義了以下函數(shù):

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

返回一個 reader 對象,該對象將逐行遍歷 csvfile。csvfile 可以是任何對象,只要這個對象支持 iterator 協(xié)議并在每次調(diào)用 __next__() 方法時都返回字符串,文件對象 和列表對象均適用。如果 csvfile 是文件對象,則打開它時應(yīng)使用 newline=''。 1 可選參數(shù) dialect 是用于不同的 CSV 變種的特定參數(shù)組。它可以是 Dialect 類的子類的實例,也可以是 list_dialects() 函數(shù)返回的字符串之一。另一個可選關(guān)鍵字參數(shù) fmtparams 可以覆寫當(dāng)前變種格式中的單個格式設(shè)置。有關(guān)變種和格式設(shè)置參數(shù)的完整詳細信息,請參見 變種與格式參數(shù) 部分。

csv 文件的每一行都讀取為一個由字符串組成的列表。除非指定了 QUOTE_NONNUMERIC 格式選項(在這種情況下,未加引號的字段會轉(zhuǎn)換為浮點數(shù)),否則不會執(zhí)行自動數(shù)據(jù)類型轉(zhuǎn)換。

一個簡短的用法示例:

>>>
>>> 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 對象,該對象負責(zé)將用戶的數(shù)據(jù)在給定的文件類對象上轉(zhuǎn)換為帶分隔符的字符串。 csvfile 可以是任何具有 write() 方法的對象。 如果 csvfile 是一個文件對象,則打開它時應(yīng)使用 newline='' 1。 可以給出可選的 dialect 形參用來定義一組特定 CSV 變種專屬的形參。 它可以是 Dialect 類的某個子類的實例或是 list_dialects() 函數(shù)所返回的字符串之一。 還可以給出另一個可選的 fmtparams 關(guān)鍵字參數(shù)來覆蓋當(dāng)前變種中的單個格式化形參。 有關(guān)各個變種和格式化形參的完整細節(jié),請參閱 變種與格式參數(shù) 部分。 為了盡量簡化與實現(xiàn) DB API 的模塊之間的接口,None 值會被當(dāng)作空字符串寫入。 雖然這個轉(zhuǎn)換是不可逆的,但它可以簡化 SQL NULL 數(shù)據(jù)值到 CSV 文件的轉(zhuǎn)儲而無需預(yù)處理從 cursor.fetch* 調(diào)用返回的數(shù)據(jù)。 在被寫入之前所有其他非字符串?dāng)?shù)據(jù)都會先用 str() 來轉(zhuǎn)轉(zhuǎn)為字符串。

一個簡短的用法示例:

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 關(guān)聯(lián)起來。 name 必須是字符串。 變種的指定可以通過傳入一個 Dialect 的子類,或通過 fmtparams 關(guān)鍵字參數(shù),或是兩者同時傳入,此時關(guān)鍵字參數(shù)會覆蓋 dialect 形參。 有關(guān)變種和格式化形參的完整細節(jié),請參閱 變種與格式參數(shù) 部分。

csv.unregister_dialect(name)?

從變種注冊表中刪除 name 對應(yīng)的變種。如果 name 不是已注冊的變種名稱,則拋出 Error 異常。

csv.get_dialect(name)?

返回 name 對應(yīng)的變種。如果 name 不是已注冊的變種名稱,則拋出 Error 異常。該函數(shù)返回的是不可變的 Dialect 對象。

csv.list_dialects()?

返回所有已注冊變種的名稱。

csv.field_size_limit([new_limit])?

返回解析器當(dāng)前允許的最大字段大小。如果指定了 new_limit,則它將成為新的最大字段大小。

csv 模塊定義了以下類:

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

創(chuàng)建一個對象,該對象在操作上類似于常規(guī) reader,但是將每行中的信息映射到一個 dict,該 dict 的鍵由 fieldnames 可選參數(shù)給出。

fieldnames 參數(shù)是一個 sequence。如果省略 fieldnames,則文件 f 第一行中的值將用作字段名。無論字段名是如何確定的,字典都將保留其原始順序。

如果某一行中的字段多于字段名,則剩余數(shù)據(jù)會被放入一個列表,并與 restkey 所指定的字段名 (默認為 None) 一起保存。 如果某個非空白行的字段少于字段名,則缺失的值會使用 restval 的值來填充 (默認為 None)。

所有其他可選或關(guān)鍵字參數(shù)都傳遞給底層的 reader 實例。

在 3.6 版更改: 返回的行現(xiàn)在的類型是 OrderedDict

在 3.8 版更改: 現(xiàn)在,返回的行是 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)?

創(chuàng)建一個對象,該對象在操作上類似常規(guī) writer,但會將字典映射到輸出行。 fieldnames 參數(shù)是由鍵組成的 序列,它指定字典中值的順序,這些值會按指定順序傳遞給 writerow() 方法并寫入文件 f。 如果字典缺少 fieldnames 中的鍵,則可選參數(shù) restval 用于指定要寫入的值。 如果傳遞給 writerow() 方法的字典的某些鍵在 fieldnames 中找不到,則可選參數(shù) extrasaction 用于指定要執(zhí)行的操作。 如果將其設(shè)置為默認值 'raise',則會引發(fā) ValueError。 如果將其設(shè)置為 'ignore',則字典中的其他鍵值將被忽略。 所有其他可選或關(guān)鍵字參數(shù)都傳遞給底層的 writer 實例。

注意,與 DictReader 類不同,DictWriter 類的 fieldnames 參數(shù)不是可選參數(shù)。

一個簡短的用法示例:

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 類是一個容器類,其屬性包含有如何處理雙引號、空白符、分隔符等的信息。 由于缺少嚴(yán)格的 CSV 規(guī)格描述,不同的應(yīng)用程序會產(chǎn)生略有差別的 CSV 數(shù)據(jù)。 Dialect 實例定義了 readerwriter 實例將具有怎樣的行為。

所有可用的 Dialect 名稱會由 list_dialects() 返回,并且它們可由特定的 readerwriter 類通過它們的初始化函數(shù) (__init__) 來注冊,例如:

import csv

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

excel 類定義了 Excel 生成的 CSV 文件的常規(guī)屬性。它在變種注冊表中的名稱是 'excel'。

class csv.excel_tab?

excel_tab 類定義了 Excel 生成的、制表符分隔的 CSV 文件的常規(guī)屬性。它在變種注冊表中的名稱是 'excel-tab'。

class csv.unix_dialect?

unix_dialect 類定義了在 UNIX 系統(tǒng)上生成的 CSV 文件的常規(guī)屬性,即使用 '\n' 作為換行符,且所有字段都有引號包圍。它在變種注冊表中的名稱是 'unix'。

3.2 新版功能.

class csv.Sniffer?

Sniffer 類用于推斷 CSV 文件的格式。

Sniffer 類提供了兩個方法:

sniff(sample, delimiters=None)?

分析給定的 sample 并返回一個 Dialect 子類,該子類中包含了分析出的格式參數(shù)。如果給出可選的 delimiters 參數(shù),則該參數(shù)會被解釋為字符串,該字符串包含了可能的有效定界符。

has_header(sample)?

分析 sample 文本(假定為 CSV 格式),如果發(fā)現(xiàn)其首行為一組列標(biāo)題則返回 True。 在檢查每一列時,將考慮是否滿足兩個關(guān)鍵標(biāo)準(zhǔn)之一來估計 sample 是否包含標(biāo)題:

  • 第二至第 n 行包含數(shù)字值

  • 第二至第 n 行包含字符串值,其中至少有一個值的長度與該列預(yù)期標(biāo)題的長度不同。

會對第一行之后的二十行進行采樣;如果有超過一半的列 + 行符合標(biāo)準(zhǔn),則返回 True

備注

此方法是一個粗略的啟發(fā)式方式,有可能產(chǎn)生錯誤的真值和假值。

使用 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 對象僅為包含特殊字符(例如 定界符、引號字符行結(jié)束符 中的任何字符)的字段加上引號。

csv.QUOTE_NONNUMERIC?

指示 writer 對象為所有非數(shù)字字段加上引號。

指示 reader 將所有未用引號引出的字段轉(zhuǎn)換為 float 類型。

csv.QUOTE_NONE?

指示 writer 對象不使用引號引出字段。當(dāng) 定界符 出現(xiàn)在輸出數(shù)據(jù)中時,其前面應(yīng)該有 轉(zhuǎn)義符。如果未設(shè)置 轉(zhuǎn)義符,則遇到任何需要轉(zhuǎn)義的字符時,writer 都會拋出 Error 異常。

指示 reader 不對引號字符進行特殊處理。

csv 模塊定義了以下異常:

exception csv.Error?

該異??赡苡扇魏伟l(fā)生錯誤的函數(shù)拋出。

變種與格式參數(shù)?

為了更容易指定輸入和輸出記錄的格式,特定的一組格式參數(shù)組合為一個 dialect(變種)。一個 dialect 是一個 Dialect 類的子類,它具有一組特定的方法和一個 validate() 方法。創(chuàng)建 readerwriter 對象時,程序員可以將某個字符串或 Dialect 類的子類指定為 dialect 參數(shù)。要想補充或覆蓋 dialect 參數(shù),程序員還可以單獨指定某些格式參數(shù),這些參數(shù)的名稱與下面 Dialect 類定義的屬性相同。

Dialect 類支持以下屬性:

Dialect.delimiter?

一個用于分隔字段的單字符,默認為 ','

Dialect.doublequote?

控制出現(xiàn)在字段中的 引號字符 本身應(yīng)如何被引出。當(dāng)該屬性為 True 時,雙寫引號字符。如果該屬性為 False,則在 引號字符 的前面放置 轉(zhuǎn)義符。默認值為 True。

在輸出時,如果 doublequoteFalse,且 轉(zhuǎn)義符 未指定,且在字段中發(fā)現(xiàn) 引號字符 時,會拋出 Error 異常。

Dialect.escapechar?

一個用于 writer 的單字符,用來在 quoting 設(shè)置為 QUOTE_NONE 的情況下轉(zhuǎn)義 定界符,在 doublequote 設(shè)置為 False 的情況下轉(zhuǎn)義 引號字符。在讀取時,escapechar 去除了其后所跟字符的任何特殊含義。該屬性默認為 None,表示禁用轉(zhuǎn)義。

在 3.11 版更改: An empty escapechar is not allowed.

Dialect.lineterminator?

放在 writer 產(chǎn)生的行的結(jié)尾,默認為 '\r\n'

備注

reader 經(jīng)過硬編碼,會識別 '\r''\n' 作為行尾,并忽略 lineterminator。未來可能會更改這一行為。

Dialect.quotechar?

一個單字符,用于包住含有特殊字符的字段,特殊字符如 定界符引號字符 或換行符。默認為 '"'

在 3.11 版更改: An empty quotechar is not allowed.

Dialect.quoting?

控制 writer 何時生成引號,以及 reader 何時識別引號。該屬性可以等于任何 QUOTE_* 常量(參見 模塊內(nèi)容 段落),默認為 QUOTE_MINIMAL

Dialect.skipinitialspace?

如果為 True,則忽略 定界符 之后的空格。默認值為 False。

Dialect.strict?

如果為 True,則在輸入錯誤的 CSV 時拋出 Error 異常。默認值為 False。

Reader 對象?

Reader 對象(DictReader 實例和 reader() 函數(shù)返回的對象)具有以下公開方法:

csvreader.__next__()?

返回 reader 的可迭代對象的下一行,它可以是一個列表(如果對象是由 reader() 返回)或字典(如果是一個 DictReader 實例),根據(jù)當(dāng)前 Dialect 來解析。 通常你應(yīng)當(dāng)以 next(reader) 的形式來調(diào)用它。

Reader 對象具有以下公開屬性:

csvreader.dialect?

變種描述,只讀,供解析器使用。

csvreader.line_num?

源迭代器已經(jīng)讀取了的行數(shù)。它與返回的記錄數(shù)不同,因為記錄可能跨越多行。

DictReader 對象具有以下公開屬性:

csvreader.fieldnames?

字段名稱。如果在創(chuàng)建對象時未傳入字段名稱,則首次訪問時或從文件中讀取第一條記錄時會初始化此屬性。

Writer 對象?

Writer 對象(DictWriter 實例和 writer() 函數(shù)返回的對象)具有下面的公開方法。對于 Writer 對象, 必須是(一組可迭代的)字符串或數(shù)字。對于 DictWriter 對象, 必須是一個字典,這個字典將字段名映射為字符串或數(shù)字(數(shù)字要先經(jīng)過 str() 轉(zhuǎn)換類型)。請注意,輸出的復(fù)數(shù)會有括號包圍。這樣其他程序讀取 CSV 文件時可能會有一些問題(假設(shè)它們完全支持復(fù)數(shù))。

csvwriter.writerow(row)?

row 形參寫入到 writer 的文件對象,根據(jù)當(dāng)前 Dialect 進行格式化。 返回對下層文件對象的 write 方法的調(diào)用的返回值。

在 3.5 版更改: 開始支持任意類型的迭代器。

csvwriter.writerows(rows)?

rows*(即能迭代出多個上述 *row 對象的迭代器)中的所有元素寫入 writer 的文件對象,并根據(jù)當(dāng)前設(shè)置的變種進行格式化。

Writer 對象具有以下公開屬性:

csvwriter.dialect?

變種描述,只讀,供 writer 使用。

DictWriter 對象具有以下公開方法:

DictWriter.writeheader()?

在 writer 的文件對象中,寫入一行字段名稱(字段名稱在構(gòu)造函數(shù)中指定),并根據(jù)當(dāng)前設(shè)置的變種進行格式化。本方法的返回值就是內(nèi)部使用的 csvwriter.writerow() 方法的返回值。

3.2 新版功能.

在 3.8 版更改: 現(xiàn)在 writeheader() 也返回其內(nèi)部使用的 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)

相應(yīng)最簡單的寫入示例是:

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

Since open() is used to open a CSV file for reading, the file will by default be decoded into unicode using the system default encoding (see locale.getencoding()). To decode a file using a different encoding, use the encoding argument of open:

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

這同樣適用于寫入非系統(tǒng)默認編碼的內(nèi)容:打開輸出文件時,指定 encoding 參數(shù)。

注冊一個新的變種:

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

Reader 的更高級用法——捕獲并報告錯誤:

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)

備注

1(1,2)

如果沒有指定 newline='',則嵌入引號中的換行符將無法正確解析,并且在寫入時,使用 \r\n 換行的平臺會有多余的 \r 寫入。由于 csv 模塊會執(zhí)行自己的(通用)換行符處理,因此指定 newline='' 應(yīng)該總是安全的。