13.1. csv — CSV 文件读写

2.3 版的新Function。

所谓的 CSV(逗号分隔值)格式是电子表格和数据库最常用的导入和导出格式。由于没有“ CSV 标准”,因此该格式由许多读写该应用程序的应用程序定义。缺乏标准意味着由不同应用程序生成和使用的数据通常存在细微差异。这些差异会使处理来自多个来源的 CSV 文件变得烦人。尽管如此,尽管定界符和引号字符有所不同,但总体格式足够相似,因此有可能编写一个可以有效处理此类数据的模块,从而隐藏了对程序员进行数据读写的细节。

csv模块实现用于以 CSV 格式读取和写入表格数据的类。它使程序员可以说“以 Excel 首选的格式写入此数据”或“从 Excel 生成的此文件中读取数据”,而无需知道 Excel 所使用的 CSV 格式的确切细节。程序员还可以描述其他应用程序可以理解的 CSV 格式,或者定义自己的专用 CSV 格式。

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

Note

此版本的csv模块不支持 UnicodeImporting。另外,当前还存在一些有关 ASCII NUL 字符的问题。因此,所有 Importing 均应为 UTF-8 或可打印的 ASCII,以确保安全;请参阅Examples部分中的示例。

See also

  • PEP 305-CSV 文件 API

  • 《 Python 增强提案》提出了对 Python 的这一补充。

13.1.1. 模块内容

csv模块定义以下Function:

  • csv. reader(* csvfile dialect ='excel'** fmtparams *)
    • 返回一个读取器对象,该对象将遍历给定* csvfile *中的行。 * csvfile 可以是任何支持iterator协议并在每次调用next()方法时都返回字符串的对象-文件对象和列表对象均适用。如果 csvfile 是文件对象,则必须在有区别的平台上使用'b'标志打开它。可以提供一个可选的 dialect 参数,该参数用于定义特定于特定 CSV 方言的一组参数。它可能是Dialect类的子类的实例,或者是list_dialects()函数返回的字符串之一。可以使用其他可选的 fmtparams *关键字参数来覆盖当前方言中的各个格式设置参数。有关方言和格式设置参数的完整详细信息,请参见方言和格式参数部分。

从 csv 文件读取的每一行都作为字符串列表返回。不执行自动数据类型转换。

一个简短的用法示例:

>>> import csv
>>> with open('eggs.csv', 'rb') 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

在版本 2.5 中进行了更改:现在,对于多行引用字段,解析器更加严格。以前,如果一行在带引号的字段中结束但没有换行符终止,则将换行符插入返回的字段中。读取字段中包含回车符的文件时,此行为导致问题。行为已更改为不插入换行符即可返回该字段。因此,如果嵌入在字段中的换行很重要,则应以保留换行符的方式将 Importing 分成几行。

  • csv. writer(* csvfile dialect ='excel'** fmtparams *)
    • 返回一个 writer 对象,该对象负责将用户数据转换为给定文件状对象上的定界字符串。 * csvfile 可以是具有write()方法的任何对象。如果 csvfile 是文件对象,则必须在有区别的平台上使用'b'标志打开它。可以提供一个可选的 dialect 参数,该参数用于定义特定于特定 CSV 方言的一组参数。它可能是Dialect类的子类的实例,或者是list_dialects()函数返回的字符串之一。可以使用其他可选的 fmtparams *关键字参数来覆盖当前方言中的各个格式设置参数。有关方言和格式设置参数的完整详细信息,请参见方言和格式参数部分。为了尽可能容易地与实现 DB API 的模块接口,将值None写入为空字符串。尽管这不是可逆的转换,但它可以更轻松地将 SQL NULL 数据值转储到 CSV 文件,而无需预处理从cursor.fetch*调用返回的数据。浮点数在写入前用repr()进行字符串化。在写入之前,所有其他非字符串数据都用str()进行字符串化。

一个简短的用法示例:

import csv
with open('eggs.csv', 'wb') 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 *相关联。 * name 必须是字符串或 Unicode 对象。可以pass传递Dialect的子类或pass fmtparams *关键字参数(或两者都使用关键字参数覆盖方言的参数)来指定方言。有关方言和格式设置参数的完整详细信息,请参见方言和格式参数部分。
  • csv. unregister_dialect(* name *)

    • 从方言注册表中删除与* name 关联的方言。如果 name *不是注册的方言名称,则会引发Error
  • csv. get_dialect(* name *)

    • 返回与* name 关联的方言。如果 name *不是注册的方言名称,则会引发Error

在版本 2.5 中更改:此函数现在返回一个不可变的Dialect。以前,返回了所请求方言的一个实例。用户可以修改基础类,从而更改活动的读取器和写入器的行为。

  • csv. list_dialects ( )

    • 返回所有已注册方言的名称。
  • csv. field_size_limit([* new_limit *])

    • 返回解析器允许的当前最大字段大小。如果给定* new_limit *,它将成为新的限制。

2.5 版的新Function。

csv模块定义以下类别:

    • class * csv. DictReader(* f fieldnames = None restkey = None restval = None dialect ='excel'*, *args * kwds *)
    • 创建一个对象,其Function类似于常规读取器,但将读取的信息 Map 到字典中,该字典的键由可选的* fieldnames *参数给出。 * fieldnames 参数是sequence,其元素按 Sequences 与 Importing 数据的字段关联。这些元素成为结果字典的键。如果Ellipsis fieldnames 参数,则文件 f 第一行中的值将用作字段名。如果读取的行中的字段多于字段名序列,则其余数据将添加为一个序列,并以 restkey 的值作为键。如果读取的行中的字段少于字段名序列,则其余键采用可选的 restval *参数的值。其他任何可选参数或关键字参数都将传递到基础reader实例。

一个简短的用法示例:

>>> import csv
>>> with open('names.csv') as csvfile:
...     reader = csv.DictReader(csvfile)
...     for row in reader:
...         print(row['first_name'], row['last_name'])
...
Baked Beans
Lovely Spam
Wonderful Spam
    • class * csv. DictWriter(* f fieldnames restval ='' extrasaction ='raise' dialect ='excel'*, *args * kwds *)
    • 创建一个操作类似于常规编写器的对象,但将字典 Map 到输出行。 * fieldnames 参数是sequence键,这些键标识传递给writerow()方法的字典中的值写入文件 f 的 Sequences。可选的 restval 参数指定如果字典缺少 fieldnames 中的键时要写入的值。如果传递给writerow()方法的词典包含在 fieldnames 中找不到的键,则可选的 extrasaction *参数指示要执行的操作。如果将其设置为'raise',则会引发ValueError。如果将其设置为'ignore',则字典中的其他值将被忽略。其他任何可选参数或关键字参数都将传递到基础writer实例。

请注意,与DictReader类不同,DictWriter的* fieldnames 参数不是可选的。由于未对 Python 的dict对象进行排序,因此没有足够的信息来推断应将行写入文件 f *的 Sequences。

一个简短的用法示例:

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'})
  • 类别 csv. Dialect

    • Dialect类是主要用于其属性的容器类,该属性用于定义特定readerwriter实例的参数。
  • 类别 csv. excel

    • excel类定义 Excel 生成的 CSV 文件的常规属性。它以方言名称'excel'注册。
  • 类别 csv. excel_tab

    • excel_tab类定义 Excel 生成的 TAB 分隔文件的常规属性。它以方言名称'excel-tab'注册。
  • 类别 csv. Sniffer

    • Sniffer类用于推断 CSV 文件的格式。

Sniffer类提供了两种方法:

  • sniff(* sample delimiters = None *)

    • 分析给定的* sample 并返回一个Dialect子类,以反映找到的参数。如果给出了可选的 delimiters *参数,则将其解释为包含可能的有效分隔符的字符串。
  • has_header(samples)

    • 分析示例文本(假定为 CSV 格式),如果第一行似乎是一系列列标题,则返回True

Sniffer使用的示例:

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

指示 Reader 将所有未引用的字段转换为* float *类型。

  • csv. QUOTE_NONE
    • 指示writer个对象从不引用字段。当当前分隔符出现在输出数据中时,它前面是当前* escapechar 字符。如果未设置 escapechar *,则如果遇到任何需要转义的字符,编写器将引发Error

指示reader不对引号字符进行特殊处理。

csv模块定义以下异常:

  • exception csv. Error
    • 检测到错误时由任何Function引发。

13.1.2. 方言和格式参数

为了更轻松地指定 Importing 和输出记录的格式,将特定的格式设置参数组合为方言。方言是Dialect类的子类,它具有一组特定方法和一个validate()方法。创建readerwriter对象时,程序员可以将字符串或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,这将禁用转义。
  • Dialect. lineterminator

    • 用于终止writer产生的行的字符串。默认为'\r\n'

Note

reader被硬编码为将'\r''\n'识别为行尾,并忽略* lineterminator *。这种行为将来可能会改变。

  • Dialect. quotechar

    • 一个单字符字符串,用于引用包含特殊字符(例如* delimiter quotechar *)或包含换行符的字段。默认为'"'
  • Dialect. quoting

    • 控制引号何时由作者生成并由 Reader 识别。它可以采用任何QUOTE_*常量(请参见Module Contents),默认为QUOTE_MINIMAL
  • Dialect. skipinitialspace

    • True时,紧跟在* delimiter *之后的空格将被忽略。默认值为False
  • Dialect. strict

    • True时,对于错误的 CSVImporting,引发异常Error。默认值为False

13.1.3. Reader 对象

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

  • csvreader. next ( )
    • 将 Reader 可迭代对象的下一行作为列表返回,并根据当前方言进行解析。

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

  • csvreader. dialect

    • 解析器使用的方言的只读描述。
  • csvreader. line_num

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

2.5 版的新Function。

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

  • csvreader. fieldnames
    • 如果在创建对象时未将其作为参数传递,则该属性将在首次访问时或从文件中读取第一条记录时初始化。

在 2.6 版中进行了更改。

13.1.4. Writer 对象

Writer个对象(DictWriter个实例和writer()函数返回的对象)具有以下公共方法。 必须是Writer对象的字符串或数字序列,并且是将DictWriter对象的字段名 Map 为字符串或数字(首先passstr()传递)的字典。请注意,复数写在括号内。这可能会给其他读取 CSV 文件的程序带来一些问题(假设它们完全支持复数)。

  • csvwriter. writerow(* row *)

    • 将* row *参数写入编写者的文件对象,并根据当前方言格式化。
  • csvwriter. writerows()

    • 将* rows(如上所述,* row *对象的迭代)中的所有元素写入编写者的文件对象,并根据当前方言格式化。

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

  • csvwriter. dialect
    • 作者使用的方言的只读描述。

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

  • DictWriter. writeheader ( )
    • 用字段名称(在构造函数中指定)写一行。

2.7 版的新Function。

13.1.5. Examples

读取 CSV 文件的最简单示例:

import csv
with open('some.csv', 'rb') as f:
    reader = csv.reader(f)
    for row in reader:
        print row

读取具有其他格式的文件:

import csv
with open('passwd', 'rb') as f:
    reader = csv.reader(f, delimiter=':', quoting=csv.QUOTE_NONE)
    for row in reader:
        print row

相应的最简单的编写示例是:

import csv
with open('some.csv', 'wb') as f:
    writer = csv.writer(f)
    writer.writerows(someiterable)

注册新的方言:

import csv
csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)
with open('passwd', 'rb') as f:
    reader = csv.reader(f, 'unixpwd')

阅读器的更高级用法-捕获并报告错误:

import csv, sys
filename = 'some.csv'
with open(filename, 'rb') as f:
    reader = csv.reader(f)
    try:
        for row in reader:
            print row
    except csv.Error as e:
        sys.exit('file %s, line %d: %s' % (filename, reader.line_num, e))

尽管该模块不直接支持解析字符串,但可以轻松实现:

import csv
for row in csv.reader(['one,two,three']):
    print row

csv模块不直接支持读写 Unicode,但是它是 8 位纯净的,除了 ASCII NUL 字符的某些问题。因此,只要避免使用 NUL 的 UTF-16 之类的编码,就可以编写为您处理编码和解码的函数或类。建议使用 UTF-8.

下面的unicode_csv_reader()generator,它包装csv.reader以处理 Unicode CSV 数据(Unicode 字符串列表)。 utf_8_encoder()generator,它将 Unicode 字符串编码为 UTF-8,一次编码一个字符串(或一行)。编码的字符串由 CSV 阅读器解析,并且unicode_csv_reader()将 UTF-8 编码的单元解码回 Unicode:

import csv

def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs):
    # csv.py doesn't do Unicode; encode temporarily as UTF-8:
    csv_reader = csv.reader(utf_8_encoder(unicode_csv_data),
                            dialect=dialect, **kwargs)
    for row in csv_reader:
        # decode UTF-8 back to Unicode, cell by cell:
        yield [unicode(cell, 'utf-8') for cell in row]

def utf_8_encoder(unicode_csv_data):
    for line in unicode_csv_data:
        yield line.encode('utf-8')

对于所有其他编码,可以使用以下UnicodeReaderUnicodeWriter类。他们在构造函数中采用了额外的* encoding *参数,并确保数据pass编码为 UTF-8 的真实读取器或写入器:

import csv, codecs, cStringIO

class UTF8Recoder:
    """
    Iterator that reads an encoded stream and reencodes the input to UTF-8
    """
    def __init__(self, f, encoding):
        self.reader = codecs.getreader(encoding)(f)

    def __iter__(self):
        return self

    def next(self):
        return self.reader.next().encode("utf-8")

class UnicodeReader:
    """
    A CSV reader which will iterate over lines in the CSV file "f",
    which is encoded in the given encoding.
    """

    def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
        f = UTF8Recoder(f, encoding)
        self.reader = csv.reader(f, dialect=dialect, **kwds)

    def next(self):
        row = self.reader.next()
        return [unicode(s, "utf-8") for s in row]

    def __iter__(self):
        return self

class UnicodeWriter:
    """
    A CSV writer which will write rows to CSV file "f",
    which is encoded in the given encoding.
    """

    def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
        # Redirect output to a queue
        self.queue = cStringIO.StringIO()
        self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
        self.stream = f
        self.encoder = codecs.getincrementalencoder(encoding)()

    def writerow(self, row):
        self.writer.writerow([s.encode("utf-8") for s in row])
        # Fetch UTF-8 output from the queue ...
        data = self.queue.getvalue()
        data = data.decode("utf-8")
        # ... and reencode it into the target encoding
        data = self.encoder.encode(data)
        # write to the target stream
        self.stream.write(data)
        # empty queue
        self.queue.truncate(0)

    def writerows(self, rows):
        for row in rows:
            self.writerow(row)