Skip to main content

14.1. csv — CSV文件读写

源代码: Lib/csv.py


所谓的CSV(逗号分隔值)格式是电子表格和数据库最常见的导入和导出格式。 CSV格式在尝试以 RFC 4180 中的标准化方式描述格式之前使用多年。缺乏明确定义的标准意味着在不同应用产生和消费的数据中通常存在细微的差异。这些差异可能会让处理来自多个来源的CSV文件烦人。尽管分隔符和引用字符不同,但是整体格式是足够相似的,以致于可以编写能够有效地操作这样的数据的单个模块,隐藏从编程器读取和写入数据的细节。

csv 模块实现以CSV格式读取和写入表格数据的类。它允许程序员说,“以Excel首选的格式写入数据”或“从Excel生成的此文件中读取数据”,而不知道Excel使用的CSV格式的确切详细信息。程序员还可以描述其他应用程序理解的CSV格式,或定义自己的特殊用途CSV格式。

csv 模块的 readerwriter 对象读取和写入序列。程序员还可以使用 DictReaderDictWriter 类以字典形式读取和写入数据。

参见

PEP 305 - CSV文件API

Python Enhancement Proposal提出了对Python的添加。

14.1.1. 模块内容

csv 模块定义以下功能:

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

返回一个读者对象,它将迭代给定的 csvfile 中的行。 csvfile 可以是支持 iterator 协议并且每次调用 __next__() 方法时返回字符串的任何对象— 文件对象 和列表对象都是合适的。如果 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(csvfile, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds)

创建一个像常规阅读器一样操作的对象,但将每行中的信息映射到 OrderedDict,其键由可选的 fieldnames 参数给出。

fieldnames 参数是 sequence。如果省略 fieldnames,则 csvfile 第一行中的值将用作字段名称。无论如何确定字段名,有序字典保留其原始排序。

如果行的字段数多于字段名称,则剩余数据将被放入列表中,并使用由 restkey (默认为 None)指定的字段名称存储。如果非空行的字段少于字段名,则缺少的值将使用 None 填充。

所有其他可选或关键字参数传递给基础 reader 实例。

在 3.6 版更改: 返回的行现在是 OrderedDict 类型。

一个简短的用法示例:

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

>>> print(row)
OrderedDict([('first_name', 'John'), ('last_name', 'Cleese')])
class csv.DictWriter(csvfile, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwds)

创建一个像普通的writer一样操作的对象,但把字典映射到输出行上。 fieldnames 参数是键的 sequence,其标识传递给 writerow() 方法的字典中的值被写入 csvfile 的顺序。如果字典在 fieldnames 中缺少键,则可选的 restval 参数指定要写入的值。如果传递给 writerow() 方法的字典包含在 fieldnames 中未找到的键,则可选的 extrasaction 参数指示要采取的操作。如果设置为 'raise',则默认值为 ValueError。如果设置为 'ignore',则字典中的额外值将被忽略。任何其他可选或关键字参数传递给底层 writer 实例。

注意,与 DictReader 类不同,DictWriterfieldnames 参数不是可选的。由于Python的 dict 对象没有排序,因此没有足够的信息来推断应该将行写入 csvfile 的顺序。

一个简短的用法示例:

import csv

with open('names.csv', 'w') 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 类是一个主要依赖于其属性的容器类,用于定义特定 readerwriter 实例的参数。

class csv.excel

excel 类定义Excel生成的CSV文件的常用属性。它用方言名称 'excel' 注册。

class csv.excel_tab

excel_tab 类定义了Excel生成的TAB分隔文件的常用属性。它用方言名称 '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

Sniffer 使用的一个例子:

with open('example.csv') 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 对象引用所有非数字字段。

指示读者将所有非引用字段转换为类型 float

csv.QUOTE_NONE

指示 writer 对象从不引用字段。当输出数据中出现当前 delimiter 时,其前面是当前 escapechar 字符。如果未设置 escapechar,则在遇到需要转义的任何字符时,写入程序将提高 Error

指示 reader 不执行引号字符的特殊处理。

csv 模块定义了以下异常:

exception csv.Error

检测到错误时由任何函数引发。

14.1.2. 方言和格式化参数

为了更容易指定输入和输出记录的格式,特定的格式化参数被分组到方言中。方言是 Dialect 类的子类,具有一组特定方法和单个 validate() 方法。当创建 readerwriter 对象时,程序员可以指定 Dialect 类的字符串或子类作为方言参数。除了或替代 dialect 参数,程序员还可以指定单独的格式化参数,其具有与下面针对 Dialect 类定义的属性相同的名称。

方言支持以下属性:

Dialect.delimiter

用于分隔字段的单字符字符串。它默认为 ','

Dialect.doublequote

控制在字段中出现的 quotechar 的实例本身应如何引用。当 True 时,字符加倍。当 False 时,escapechar 用作 quotechar 的前缀。它默认为 True

在输出上,如果 doublequoteFalse 并且没有设置 escapechar,则如果在字段中发现 quotechar,则引发 Error

Dialect.escapechar

如果 quoting 设置为 QUOTE_NONE,作者使用一个字符串来转义 delimiter,如果 doublequoteFalse,则使用 quotechar。阅读时,escapechar 会删除以下字符中的任何特殊含义。它默认为 None,它禁用转义。

Dialect.lineterminator

用于终止由 writer 生成的行的字符串。它默认为 '\r\n'

注解

reader 是硬编码的,以识别 '\r''\n' 作为行尾,并忽略 lineterminator。此行为可能会在将来更改。

Dialect.quotechar

用于引用包含特殊字符(例如 delimiterquotechar)或包含新行字符的字段的单字符字符串。它默认为 '"'

Dialect.quoting

控制报价应由作者生成并由读者识别。它可以接受任何 QUOTE_* 常量(参见 模块内容 部分),默认为 QUOTE_MINIMAL

Dialect.skipinitialspace

True,紧跟在 delimiter 之后的空白被忽略。默认值为 False

Dialect.strict

True 时,在错误的CSV输入上引发异常 Error。默认值为 False

14.1.3. 阅读器对象

Reader对象(DictReader 实例和 reader() 函数返回的对象)具有以下公共方法:

csvreader.__next__()

返回读者的可迭代对象的下一行作为列表,根据当前方言解析。通常你应该把它叫做 next(reader)

Reader对象具有以下公共属性:

csvreader.dialect

解析器使用的方言的只读描述。

csvreader.line_num

从源迭代器读取的行数。这与返回的记录数不同,因为记录可以跨越多行。

DictReader对象具有以下公共属性:

csvreader.fieldnames

如果在创建对象时未作为参数传递,则在首次访问时或从文件读取第一个记录时初始化此属性。

14.1.4. 作者对象

Writer 对象(DictWriter 实例和 writer() 函数返回的对象)具有以下公共方法。 row 必须是 Writer 对象的字符串或数字的可迭代字符串,以及将字符串映射到 DictWriter 对象的字符串或字符串(通过将它们传递通过 str())。注意,复数用柔义包围。这可能会导致一些问题,其他程序读取CSV文件(假设他们支持复数)。

csvwriter.writerow(row)

row 参数写入写入程序的文件对象,根据当前方言格式化。

在 3.5 版更改: 增加了对任意迭代的支持。

csvwriter.writerows(rows)

将所有 rows 参数(如上所述的 row 对象的列表)写入到作者的文件对象,根据当前方言格式化。

Writer对象具有以下公共属性:

csvwriter.dialect

作者使用的方言的只读描述。

DictWriter对象具有以下公共方法:

DictWriter.writeheader()

用字段名写入一行(在构造函数中指定)。

3.2 新版功能.

14.1.5. 例子

读取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.getpreferredencoding())解码为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)

这同样适用于在非系统默认编码以外的东西写:打开输出文件时,指定编码参数。

注册新方言:

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)

脚注

[1](1, 2)

如果未指定 newline='',则嵌入在引用字段中的新行不会被正确解释,并且在使用 \r\n 子句的平台上写入额外的 \r 将被添加。它应该总是安全地指定 newline='',因为csv模块有自己的(普遍)换行处理。