csv --- CSV 文件讀寫?

源代碼: Lib/csv.py


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

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

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

參見

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

《Python 增強(qiáng)提議》提出了對(duì) Python 的這一補(bǔ)充。

模塊內(nèi)容?

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

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

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

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

一個(gè)簡(jiǎ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)?

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

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

csv.unregister_dialect(name)?

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

csv.get_dialect(name)?

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

csv.list_dialects()?

返回所有已注冊(cè)變種的名稱。

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)建一個(gè)對(duì)象,該對(duì)象在操作上類似于常規(guī) reader,但是將每行中的信息映射到一個(gè) dict,該 dict 的鍵由 fieldnames 可選參數(shù)給出。

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

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

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

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

在 3.8 版更改: 現(xiàn)在,返回的行是 dict 類型。

一個(gè)簡(jiǎn)短的用法示例:

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

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

一個(gè)簡(jiǎn)短的用法示例:

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

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

import csv

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

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

class csv.excel_tab?

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

class csv.unix_dialect?

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

3.2 新版功能.

class csv.Sniffer?

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

Sniffer 類提供了兩個(gè)方法:

sniff(sample, delimiters=None)?

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

has_header(sample)?

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

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

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

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

備注

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

使用 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 對(duì)象給所有字段加上引號(hào)。

csv.QUOTE_MINIMAL?

指示 writer 對(duì)象僅為包含特殊字符(例如 定界符、引號(hào)字符行結(jié)束符 中的任何字符)的字段加上引號(hào)。

csv.QUOTE_NONNUMERIC?

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

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

csv.QUOTE_NONE?

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

指示 reader 不對(duì)引號(hào)字符進(jìn)行特殊處理。

csv 模塊定義了以下異常:

exception csv.Error?

該異常可能由任何發(fā)生錯(cuò)誤的函數(shù)拋出。

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

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

Dialect 類支持以下屬性:

Dialect.delimiter?

一個(gè)用于分隔字段的單字符,默認(rèn)為 ','。

Dialect.doublequote?

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

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

Dialect.escapechar?

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

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

Dialect.lineterminator?

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

備注

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

Dialect.quotechar?

一個(gè)單字符,用于包住含有特殊字符的字段,特殊字符如 定界符引號(hào)字符 或換行符。默認(rèn)為 '"'。

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

Dialect.quoting?

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

Dialect.skipinitialspace?

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

Dialect.strict?

如果為 True,則在輸入錯(cuò)誤的 CSV 時(shí)拋出 Error 異常。默認(rèn)值為 False

Reader 對(duì)象?

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

csvreader.__next__()?

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

Reader 對(duì)象具有以下公開屬性:

csvreader.dialect?

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

csvreader.line_num?

源迭代器已經(jīng)讀取了的行數(shù)。它與返回的記錄數(shù)不同,因?yàn)橛涗浛赡芸缭蕉嘈小?/p>

DictReader 對(duì)象具有以下公開屬性:

csvreader.fieldnames?

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

Writer 對(duì)象?

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

csvwriter.writerow(row)?

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

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

csvwriter.writerows(rows)?

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

Writer 對(duì)象具有以下公開屬性:

csvwriter.dialect?

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

DictWriter 對(duì)象具有以下公開方法:

DictWriter.writeheader()?

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

3.2 新版功能.

在 3.8 版更改: 現(xiàn)在 writeheader() 也返回其內(nèi)部使用的 csvwriter.writerow() 方法的返回值。

例子?

讀取 CSV 文件最簡(jiǎn)單的一個(gè)例子:

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)最簡(jiǎn)單的寫入示例是:

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)默認(rèn)編碼的內(nèi)容:打開輸出文件時(shí),指定 encoding 參數(shù)。

注冊(cè)一個(gè)新的變種:

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

Reader 的更高級(jí)用法——捕獲并報(bào)告錯(cuò)誤:

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='',則嵌入引號(hào)中的換行符將無法正確解析,并且在寫入時(shí),使用 \r\n 換行的平臺(tái)會(huì)有多余的 \r 寫入。由于 csv 模塊會(huì)執(zhí)行自己的(通用)換行符處理,因此指定 newline='' 應(yīng)該總是安全的。