csv --- CSV 文件讀寫(xiě)?

源代碼: Lib/csv.py


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

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

csv 模塊中的 reader 類(lèi)和 writer 類(lèi)可用于讀寫(xiě)序列化的數據。也可使用 DictReader 類(lèi)和 DictWriter 類(lèi)以字典的形式讀寫(xiě)數據。

參見(jiàn)

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

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

模塊內容?

csv 模塊定義了以下函數:

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

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

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

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

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

csv.unregister_dialect(name)?

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

csv.get_dialect(name)?

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

csv.list_dialects()?

返回所有已注冊變種的名稱(chēng)。

csv.field_size_limit([new_limit])?

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

csv 模塊定義了以下類(lèi):

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

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

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

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

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

在 3.6 版更改: 返回的行現在的類(lèi)型是 OrderedDict。

在 3.8 版更改: 現在,返回的行是 dict 類(lèi)型。

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

注意,與 DictReader 類(lèi)不同,DictWriter 類(lèi)的 fieldnames 參數不是可選參數。

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

所有可用的 Dialect 名稱(chēng)會(huì )由 list_dialects() 返回,并且它們可由特定的 readerwriter 類(lèi)通過(guò)它們的初始化函數 (__init__) 來(lái)注冊,例如:

import csv

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

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

class csv.excel_tab?

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

class csv.unix_dialect?

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

3.2 新版功能.

class csv.Sniffer?

Sniffer 類(lèi)用于推斷 CSV 文件的格式。

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

sniff(sample, delimiters=None)?

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

has_header(sample)?

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

  • 第二至第 n 行包含數字值

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

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

備注

此方法是一個(gè)粗略的啟發(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 對象僅為包含特殊字符(例如 定界符、引號字符行結束符 中的任何字符)的字段加上引號。

csv.QUOTE_NONNUMERIC?

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

指示 reader 將所有未用引號引出的字段轉換為 float 類(lèi)型。

csv.QUOTE_NONE?

指示 writer 對象不使用引號引出字段。當 定界符 出現在輸出數據中時(shí),其前面應該有 轉義符。如果未設置 轉義符,則遇到任何需要轉義的字符時(shí),writer 都會(huì )拋出 Error 異常。

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

csv 模塊定義了以下異常:

exception csv.Error?

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

變種與格式參數?

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

Dialect 類(lèi)支持以下屬性:

Dialect.delimiter?

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

Dialect.doublequote?

控制出現在字段中的 引號字符 本身應如何被引出。當該屬性為 True 時(shí),雙寫(xiě)引號字符。如果該屬性為 False,則在 引號字符 的前面放置 轉義符。默認值為 True。

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

Dialect.escapechar?

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

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

Dialect.lineterminator?

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

備注

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

Dialect.quotechar?

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

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

Dialect.quoting?

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

Dialect.skipinitialspace?

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

Dialect.strict?

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

Reader 對象?

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

csvreader.__next__()?

返回 reader 的可迭代對象的下一行,它可以是一個(gè)列表(如果對象是由 reader() 返回)或字典(如果是一個(gè) DictReader 實(shí)例),根據當前 Dialect 來(lái)解析。 通常你應當以 next(reader) 的形式來(lái)調用它。

Reader 對象具有以下公開(kāi)屬性:

csvreader.dialect?

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

csvreader.line_num?

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

DictReader 對象具有以下公開(kāi)屬性:

csvreader.fieldnames?

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

Writer 對象?

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

csvwriter.writerow(row)?

row 形參寫(xiě)入到 writer 的文件對象,根據當前 Dialect 進(jìn)行格式化。 返回對下層文件對象的 write 方法的調用的返回值。

在 3.5 版更改: 開(kāi)始支持任意類(lèi)型的迭代器。

csvwriter.writerows(rows)?

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

Writer 對象具有以下公開(kāi)屬性:

csvwriter.dialect?

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

DictWriter 對象具有以下公開(kāi)方法:

DictWriter.writeheader()?

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

3.2 新版功能.

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

相應最簡(jiǎn)單的寫(xiě)入示例是:

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)

這同樣適用于寫(xiě)入非系統默認編碼的內容:打開(kāi)輸出文件時(shí),指定 encoding 參數。

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

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)

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