csv
— CSV 文件读取与写入¶
源代码: Lib/csv.py
所谓的 CSV(逗号分隔值)格式是电子表格和数据库最常用的导入和导出格式。在 RFC 4180 中尝试以标准化方式描述该格式之前,CSV 格式已经使用了许多年。缺乏明确定义的标准意味着不同应用程序生成和使用的数据中经常存在细微差异。这些差异可能会使处理来自多个来源的 CSV 文件变得很麻烦。尽管如此,虽然分隔符和引号字符各不相同,但总体格式非常相似,因此可以编写一个模块来有效地操作此类数据,从而对程序员隐藏读取和写入数据的细节。
csv
模块实现了用于以 CSV 格式读取和写入表格数据的类。它允许程序员说“以 Excel 首选的格式写入此数据”或“从此文件读取由 Excel 生成的数据”,而无需了解 Excel 使用的 CSV 格式的确切细节。程序员还可以描述其他应用程序能够理解的 CSV 格式,或定义他们自己的专用 CSV 格式。
csv
模块的 reader
和 writer
对象读取和写入序列。程序员还可以使用 DictReader
和 DictWriter
类以字典形式读取和写入数据。
另请参阅
- PEP 305 - CSV 文件 API
提议将此功能添加到 Python 的 Python 增强提案。
模块内容¶
csv
模块定义了以下函数
- csv.reader(csvfile, dialect='excel', **fmtparams)¶
返回一个 读取器对象,该对象将处理来自给定 csvfile 的行。csvfile 必须是字符串的可迭代对象,每个字符串都采用读取器定义的 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)¶
返回一个写入器对象,该对象负责将用户的数据转换为给定类文件对象上的分隔字符串。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]])¶
将 dialect 与 name 关联。name 必须是字符串。可以通过传递
Dialect
的子类、fmtparams 关键字参数或两者来指定方言,关键字参数会覆盖方言的参数。有关方言和格式参数的完整详细信息,请参阅 方言和格式参数 部分。
- 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
实例定义了reader
和writer
实例的行为方式。所有可用的
Dialect
名称都由list_dialects()
返回,并且可以通过其初始化器(__init__
)函数将它们注册到特定的reader
和writer
类,如下所示import csv with open('students.csv', 'w', newline='') as csvfile: writer = csv.writer(csvfile, dialect='unix')
- 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_NONE¶
指示
writer
对象永远不要引用字段。当当前 *delimiter* 出现在输出数据中时,它前面是当前的 *escapechar* 字符。如果未设置 *escapechar*,则如果遇到任何需要转义的字符,则 writer 将引发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
模块定义了以下异常
- 异常 csv.Error¶
当检测到错误时,由任何函数引发。
方言和格式参数¶
为了更容易地指定输入和输出记录的格式,特定的格式参数被分组到方言中。方言是 Dialect
类的子类,包含描述 CSV 文件格式的各种属性。在创建 reader
或 writer
对象时,程序员可以指定一个字符串或 Dialect
类的子类作为方言参数。除了或代替 *dialect* 参数之外,程序员还可以指定单独的格式参数,这些参数的名称与下面为 Dialect
类定义的属性相同。
方言支持以下属性
- Dialect.delimiter¶
用于分隔字段的单字符字符串。默认为
','
。
- Dialect.doublequote¶
控制字段中出现的 *quotechar* 实例本身应该如何用引号括起来。当为
True
时,字符会加倍。当为False
时,*escapechar* 将用作 *quotechar* 的前缀。默认为True
。在输出时,如果 *doublequote* 为
False
并且没有设置 *escapechar*,则如果在字段中找到 *quotechar*,则会引发Error
。
- Dialect.escapechar¶
如果 *quoting* 设置为
QUOTE_NONE
,则写入器使用单字符字符串转义 *delimiter*;如果 *doublequote* 为False
,则转义 *quotechar*。在读取时,*escapechar* 会删除后续字符的任何特殊含义。默认为None
,这将禁用转义。在 3.11 版更改: 不允许使用空的 *escapechar*。
- Dialect.lineterminator¶
writer
生成的行用来终止的字符串。默认为'\r\n'
。注意
reader
被硬编码为识别'\r'
或'\n'
为行尾,并忽略 *lineterminator*。此行为将来可能会更改。
- Dialect.quotechar¶
用于将包含特殊字符(例如 *delimiter* 或 *quotechar*)或包含换行符的字段括起来的单字符字符串。默认为
'"'
。在 3.11 版更改: 不允许使用空的 *quotechar*。
- Dialect.quoting¶
控制写入器何时应该生成引号以及读取器何时应该识别引号。它可以采用任何 QUOTE_* 常量,默认为
QUOTE_MINIMAL
。
读取器对象¶
读取器对象(DictReader
实例和由 reader()
函数返回的对象)具有以下公共方法
- csvreader.__next__()¶
根据当前的
Dialect
,将读取器可迭代对象的下一行作为列表(如果对象是从reader()
返回的)或字典(如果是DictReader
实例)返回,并进行解析。通常,您应该将其称为next(reader)
。
读取器对象具有以下公共属性
- csvreader.dialect¶
解析器正在使用的方言的只读描述。
- csvreader.line_num¶
从源迭代器读取的行数。这与返回的记录数不同,因为记录可以跨越多行。
DictReader 对象具有以下公共属性
- DictReader.fieldnames¶
如果在创建对象时未作为参数传递,则此属性将在首次访问或从文件读取第一条记录时初始化。
写入器对象¶
writer
对象(DictWriter
实例和由 writer()
函数返回的对象)具有以下公共方法。对于 writer
对象,行必须是字符串或数字的可迭代对象;对于 DictWriter
对象,行必须是将字段名映射到字符串或数字的字典(通过先将它们传递给 str()
)。请注意,复数在写入时会用括号括起来。这可能会给其他读取 CSV 文件的程序带来一些问题(假设它们 überhaupt 支持复数)。
- csvwriter.writerow(row)¶
将 row 参数写入写入器的文件对象,格式根据当前的
Dialect
。返回对底层文件对象的 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 文件进行读取,因此默认情况下,文件将使用系统默认编码解码为 Unicode(请参阅 locale.getencoding()
)。要使用不同的编码解码文件,请使用 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)
脚注