Python:CSV文件读取和写入
所谓的CSV(逗号分隔值)格式是电子表格和数据库最常用的导入和导出格式。在试图在RFC 4180中以标准化方式描述该格式之前,CSV格式已使用多年。缺乏定义明确的标准意味着不同应用程序生成和使用的数据往往存在细微差异。这些差异可能会使处理来自多个来源的CSV文件变得很烦人。不过,虽然分隔符和引号字符各不相同,但总体格式足够相似,因此可以编写单个模块来有效地操作此类数据,从而对程序员隐藏读写数据的细节。
CSV模块实现了读写CSV格式的表格数据的类。它允许程序员说,“以Excel首选的格式写入此数据”,或“从Excel生成的此文件中读取数据”,而无需了解Excel使用的CSV格式的确切细节。程序员还可以描述其他应用程序理解的CSV格式,或者定义他们自己的专用CSV格式。
CSV模块的读取器和写入器对象读取和写入序列。程序员还可以使用DictReader和DictWriter类以字典形式读取和写入数据。
Python 3:CSV文件读取和写入英文版-新版。
Python 2:CSV文件读取和写入英文版-旧版。
本篇文章为新版的中文版本。
亦见:
PEP 305 – CSV文件API。
Python增强提案提出了对Python进行此添加的建议。
模块内容
CSV模块定义了以下功能:
csv.reader(csvfile, dialect=’excel’, **fmtparams)
返回一个读取器对象,该对象将迭代给定csvfile中的行。csvfile可以是任何支持迭代器协议的对象,并在每次调用其__next__()
方法时返回一个字符串-文件对象和列表对象都适用。如果csvfile是文件对象,则应使用newline=''
打开它。可以给出可选的dialect参数,该参数用于定义特定于特定CSV dialect的一组参数。它可以是dialect类的子类的实例,也可以是LIST_DIACTIONS()
函数返回的字符串之一。可以给出其他可选的fmtparams关键字参数,以覆盖当前dialect中的各个格式化参数。有关dialect和格式参数的完整详细信息,请参阅“Dialects and Formatting Parameters(方言和格式参数)”一节。
从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=''
打开它。可以给出可选的dialect参数,该参数用于定义特定于特定CSV dialect的一组参数。它可以是dialect类的子类的实例,也可以是LIST_DIACTIONS()
函数返回的字符串之一。可以给出其他可选的fmtparams
关键字参数,以覆盖当前dialect中的各个格式化参数。有关dialect和格式参数的完整详细信息,请参阅“Dialects and Formatting Parameters(方言和格式参数)”一节。为了尽可能容易地与实现DBAPI的模块接口,值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和名称联系起来。名称必须是字符串。可以通过传递dialect的子类来指定dialect,也可以通过fmtparams关键字参数指定dialect,也可以同时使用关键字参数覆盖dialect参数来指定dialect。有关dialect和格式参数的完整详细信息,请参阅“Dialects and Formatting Parameters(方言和格式参数)”一节。
csv.unregister_dialect(name)
从dialect注册表中删除与名称关联的dialect。如果名称不是注册的dialect名称,则会引发错误。
csv.get_dialect(name)
返回与名称关联的dialect。如果名称不是注册的dialect名称,则会引发错误。此函数返回不变的dialect。
csv.list_dialects()
返回所有注册dialect的名称。
csv.field_size_limit([new_limit])
返回分析器允许的当前最大字段大小。如果给定了new_limit,则它将成为新的限制。
CSV模块定义以下类:
class csv.DictReader(f, fieldnames=None, restkey=None, restval=None, dialect=’excel’, *args, **kwds)
创建一个操作方式与常规读取器类似的对象,但将每行中的信息映射到一个字典,该字典的键由可选的fieldames
参数给出。
fieldames
参数是一个序列。如果省略fieldname
,则文件f第一行中的值将用作字段名。无论字段名是如何确定的,字典都会保留其原始顺序。
如果行中的字段多于字段名,则剩余的数据将放入一个列表中,并使用restkey
指定的字段名(默认为无)进行存储。如果非空行的字段数少于字段名,则缺少的值将使用restval
的值(默认为None)填充。
所有其他可选参数或关键字参数都传递给基础读取器实例。
版本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)
创建一个操作方式与常规编写器类似的对象,但将字典映射到输出行。fieldname
参数是一个键序列,用于标识传递给writerow()
方法的字典中的值写入文件f的顺序。可选的restval
参数指定在字典的字段名中缺少键时要写入的值。如果传递给writerow()
方法的字典包含在字段名中找不到的键,则可选的extrasaction
参数指示要采取的操作。如果它设置为默认值‘raise’,则会引发ValueError。如果将其设置为‘ignore’,则忽略字典中的多余值。任何其他可选参数或关键字参数都将传递给基础编写器实例。
请注意,与DictReader类不同,DictWriter类的fieldames
参数不是可选的。
以下是一个简短的用法示例:
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类是主要依赖于其属性的容器类,这些属性用于定义特定读取器或写入器实例的参数。
class csv.excel
excel类定义Excel生成的CSV文件的常见属性。它是用dialect名称‘excel’注册的。
class csv.excel_tab
excel_tab类定义Excel生成的TAB分隔文件的常见属性。它是用dialect名称‘excel-tab’注册的。
class csv.unix_dialect
unix_dialect类别定义在UNIX系统上生成的CSV文件的常见属性,即使用‘\n’作为行终止符并引用所有字段。它是用dialect名称“unix”注册的。
3.2版新增。
class csv.Sniffer
Sniffer类用于推断CSV文件的格式。
Sniffer类提供两种方法:
- sniff(sample, delimiters=None)
分析给定的示例并返回反映找到的参数的方言子类。如果给出了可选的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
指示写入器对象引用所有字段。
csv.QUOTE_MINIMAL
指示写入器对象仅引用包含特殊字符(如分隔符、引号或行终止符中的任何字符)的字段。
csv.QUOTE_NONNUMERIC
指示写入器对象将所有非数字字段引起来。
指示读取器将所有非引号字段转换为浮点类型。
csv.QUOTE_NONE
指示写入器对象永远不要引用字段。当当前分隔符出现在输出数据中时,它的前面是当前转义字符。如果未设置ESCRECHAR,则在遇到任何需要转义的字符时,编写器将引发错误。
指示读取器不执行引号字符的特殊处理。
CSV模块定义以下异常:
exception csv.Error
检测到错误时由任何函数引发。
Dialects and Formatting Parameters(方言和格式参数)
为了更容易地指定输入和输出记录的格式,将特定的格式化参数分组到不同的方言中。dialect是dialect类的子类,它具有一组特定的方法和一个Validation()方法。创建读取器或写入器对象时,程序员可以指定字符串或dialect类的子类作为dialect参数。除了dialect参数之外,或者代替dialect参数,程序员还可以指定各个格式化参数,这些参数与下面为dialect类定义的属性具有相同的名称。
Dialects支持以下属性:
Dialect.delimiter
用于分隔字段的单字符字符串。它默认为 ‘,’。
Dialect.doublequote
控制字段内出现的quotechar实例本身的引号方式。如果为True,则字符加倍。如果为False,则将转义字符用作报价字符的前缀。默认为True。
在输出时,如果doublequote为false并且未设置转义字符,则在字段中发现报价字符时将引发错误。
Dialect.escapechar
一个单字符字符串,如果QUOTING设置为QUOTE_NONE
,则编写器用于转义分隔符;如果Doublequote设置为False,则用于转义QUOTEChar。在阅读时,换行符从后面的字符中删除任何特殊含义。它的默认值为NONE,这将禁用转义。
Dialect.lineterminator
用于终止由写入器生成的行的字符串。默认为’\r\n’。
注意:读取是硬编码的,可以将‘\r’或‘\n’识别为行尾,并忽略行终止符。这一行为在未来可能会改变。
Dialect.quotechar
用于引用包含特殊字符(如分隔符或引号)或包含换行符的字段的单字符字符串。默认为'”‘。
Dialect.quoting
控制何时应由写入器生成引号并由读取器识别。它可以采用任何QUOTE_*常量(参见模块内容一节),并默认为QUOTE_MINIMAL
。
Dialect.skipinitialspace
如果为True,则忽略紧跟在分隔符后面的空格。默认值为False。
Dialect.strict
如果为True,则对错误的CSV输入引发异常错误。默认值为False。
读取器对象
Reader对象(DictReader
实例和由Reader()
函数返回的对象)具有以下公共方法:
csvreader.__next__()
返回读取器的可迭代对象的下一行作为列表(如果该对象是从reader()
返回的)或DICT(如果它是DictReader实例),并根据当前方言进行解析。通常,您应该将其称为next(reader)
。
读取器对象具有以下公共属性:
csvreader.dialect
解析器使用的dialect的只读描述。
csvreader.line_num
从源迭代器读取的行数。这与返回的记录数不同,因为记录可以跨越多行。
DictReader对象具有以下公共属性:
csvreader.fieldnames
如果在创建对象时未作为参数传递,则此属性在第一次访问或从文件中读取第一条记录时初始化。
写入器对象
Writer对象(DictWriter实例和writer()
函数返回的对象)具有以下公共方法。对于Writer对象,行必须是字符串或数字的可迭代;对于DictWriter对象,行必须是将字段名映射到字符串或数字(首先通过str()
传递它们)的字典。请注意,复数写出时会用括号括起来。这可能会给读取CSV文件的其他程序带来一些问题(假设它们完全支持复数)。
csvwriter.writerow(row)
将ROW参数写入写入器的文件对象,根据当前dialect格式化。返回调用底层文件对象的write方法的返回值。
版本3.5中的更改:添加了对任意迭代的支持。
csvwriter.writerows(rows)
将ROWS(如上所述的ROW对象的可迭代)中的所有元素写入写入器的文件对象,并根据当前dialect进行格式化。
写入器对象具有以下公共属性:
csvwriter.dialect
写入器使用的dialect的只读描述。
DictWriter对象具有以下公共方法:
DictWriter.writeheader()
将具有字段名称(在构造函数中指定)的行写入写入器的文件对象,并根据当前dialect格式化。返回内部使用的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.getpreredencoding())。要使用不同的编码对文件进行解码,请使用open的编码参数:
import csv with open('some.csv', newline='', encoding='utf-8') as f: reader = csv.reader(f) for row in reader: print(row)
这同样适用于写入系统默认编码以外的内容:在打开输出文件时指定编码参数。
注册新dialect:
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)
脚注
如果未指定newline=”,则将无法正确解释嵌入在带引号的字段中的换行符,并且在使用\r\n写入时使用换行的平台上,\r将添加额外的\r行。指定newline=”应该总是安全的,因为CSV模块执行自己的(通用)换行符处理。