14.1. csv — CSV 文件读写 — Python 文档
14.1. 文件 — CSV 文件读写
源代码: :source:`Lib/csv.py`
所谓的 CSV(逗号分隔值)格式是电子表格和数据库最常见的导入和导出格式。 在 RFC 4180 中尝试以标准化方式描述格式之前,CSV 格式已使用多年。 缺乏明确定义的标准意味着不同应用程序产生和使用的数据往往存在细微差别。 这些差异会使处理来自多个来源的 CSV 文件变得烦人。 尽管如此,虽然分隔符和引用字符各不相同,但整体格式足够相似,以至于可以编写一个可以有效操作此类数据的模块,从而对程序员隐藏读取和写入数据的细节。
csv 模块实现类以读取和写入 CSV 格式的表格数据。 它允许程序员说“以 Excel 首选的格式写入此数据”或“从 Excel 生成的此文件中读取数据”,而无需知道 Excel 使用的 CSV 格式的确切细节。 程序员还可以描述其他应用程序可以理解的 CSV 格式或定义自己的专用 CSV 格式。
csv 模块的 reader 和 writer 对象读取和写入序列。 程序员还可以使用 DictReader 和 DictWriter 类以字典形式读取和写入数据。
14.1.1. 模块内容
csv 模块定义了以下函数:
- csv.reader(csvfile, dialect='excel', **fmtparams)
返回一个读取器对象,该对象将遍历给定的 csvfile 中的行。 csvfile 可以是任何支持 iterator 协议并在每次调用其
__next__()
方法时返回一个字符串的对象——file objects 和 list objects两者都合适。 如果 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]])
- 将 方言 与 名称 相关联。 name 必须是字符串。 可以通过传递 Dialect 的子类或通过 fmtparams 关键字参数或两者来指定方言,并使用关键字参数覆盖方言的参数。 有关方言和格式参数的完整详细信息,请参阅 方言和格式参数 部分。
- csv.unregister_dialect(name)
- 从方言注册表中删除与 name 关联的方言。 如果 name 不是已注册的方言名称,则会引发 Error。
- 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)
创建一个对象,其操作类似于常规读取器,但将每一行中的信息映射到 OrderedDict,其键由可选的 fieldnames 参数给出。
fieldnames 参数是一个 序列 。 如果省略 fieldnames,则将使用文件 f 第一行中的值作为字段名。 不管如何确定字段名,有序字典都会保留其原始顺序。
如果一行的字段数多于字段名,则剩余的数据将放入一个列表中,并以 restkey(默认为
None
)指定的字段名存储。 如果非空行的字段数少于字段名,则用None
填充缺失值。所有其他可选或关键字参数都传递给底层 reader 实例。
在 3.6 版更改:返回的行现在是
OrderedDict
类型。一个简短的用法示例:
>>> 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) OrderedDict([('first_name', 'John'), ('last_name', 'Cleese')])
- class csv.DictWriter(f, fieldnames, restval=, extrasaction='raise', dialect='excel', *args, **kwds)
创建一个对象,其操作类似于常规编写器,但将字典映射到输出行。 fieldnames 参数是键的 序列,用于标识传递给
writerow()
方法的字典中的值写入文件 f 的顺序]。 可选的 restval 参数指定在字典缺少 fieldnames 中的键时要写入的值。 如果传递给writerow()
方法的字典包含在 fieldnames 中找不到的键,则可选的 extrasaction 参数指示要采取的操作。 如果设置为'raise'
(默认值),则会引发 ValueError。 如果设置为'ignore'
,则字典中的额外值将被忽略。 任何其他可选或关键字参数都传递给底层 writer 实例。请注意,与 DictReader 类不同,DictWriter 的 fieldnames 参数不是可选的。 由于 Python 的 dict 对象没有排序,因此没有足够的信息来推断该行应该被写入文件 f 的顺序。
一个简短的用法示例:
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.excel
- excel 类定义了 Excel 生成的 CSV 文件的常用属性。 它以方言名称
'excel'
注册。
- class csv.excel_tab
- excel_tab 类定义 Excel 生成的制表符分隔文件的常用属性。 它以方言名称
'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', 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 对象仅引用包含特殊字符的字段,例如 delimiter、quotechar 或 lineterminator 中的任何字符。
- csv.QUOTE_NONNUMERIC
指示 writer 对象引用所有非数字字段。
指示读者将所有未引用的字段转换为类型 float。
- csv.QUOTE_NONE
指示 writer 对象从不引用字段。 当当前的 分隔符 出现在输出数据中时,它前面是当前的 escapechar 字符。 如果未设置 escapechar,则在遇到任何需要转义的字符时,编写器将引发 Error。
指示 reader 不对引号字符进行特殊处理。
csv 模块定义了以下异常:
- exception csv.Error
- 检测到错误时由任何函数引发。
14.1.2. 方言和格式参数
为了更容易地指定输入和输出记录的格式,特定的格式参数被组合到方言中。 方言是 Dialect 类的子类,具有一组特定方法和一个 validate()
方法。 在创建 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 和 quotechar 如果 双引号 是假。 读取时,escapechar 会删除以下字符的任何特殊含义。 它默认为 None,禁用转义。
- Dialect.lineterminator
用于终止由 writer 生成的行的字符串。 默认为
'\r\n'
。笔记
reader 被硬编码以将
'\r'
或'\n'
识别为行尾,并忽略 lineterminator。 这种行为将来可能会改变。
- Dialect.quotechar
- 用于引用包含特殊字符(例如 delimiter 或 quotechar)或包含换行符的字段的单字符字符串。 默认为
'"'
。
- Dialect.quoting
- 控制何时应由作者生成引号并由读者识别。 它可以采用任何
QUOTE_*
常量(请参阅 模块内容 部分)并默认为 QUOTE_MINIMAL。
- Dialect.strict
- 当
True
时,在错误的 CSV 输入上引发异常 Error。 默认值为False
。
14.1.3. 读者对象
Reader 对象(DictReader 实例和由 reader() 函数返回的对象)具有以下公共方法:
- csvreader.__next__()
- 以列表(如果对象是从 reader() 返回)或字典(如果是 DictReader 实例)的形式返回下一行 reader 的可迭代对象,根据解析现在的方言。 通常你应该把它称为
next(reader)
。
Reader 对象具有以下公共属性:
- csvreader.dialect
- 解析器使用的方言的只读描述。
- csvreader.line_num
- 从源迭代器读取的行数。 这与返回的记录数不同,因为记录可以跨越多行。
DictReader 对象具有以下公共属性:
- csvreader.fieldnames
- 如果在创建对象时未作为参数传递,则在第一次访问或从文件中读取第一条记录时初始化此属性。
14.1.4. 写入器对象
Writer
对象(DictWriter 实例和 writer() 函数返回的对象)具有以下公共方法。 row 必须是 Writer
对象的字符串或数字的可迭代对象和将字段名映射到字符串或数字的字典(首先通过 str() 传递它们) DictWriter 对象。 请注意,写出的复数被括号括起来。 这可能会导致其他读取 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 文件进行读取,因此文件将默认使用系统默认编码解码为 unicode(参见 locale.getpreferredencoding())。 要使用不同的编码解码文件,请使用 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 模块执行自己的 (universal) 换行处理。