13.1. csv — CSV 文件读写 — Python 文档

来自菜鸟教程
Python/docs/2.7/library/csv
跳转至:导航、​搜索

13.1. 文件 — CSV 文件读写

2.3 版中的新功能。


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

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

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

笔记

此版本的 csv 模块不支持 Unicode 输入。 此外,目前存在一些有关 ASCII NUL 字符的问题。 因此,所有输入都应该是 UTF-8 或可打印的 ASCII 以确保安全; 请参阅 示例 部分中的示例。


也可以看看

PEP 305 - CSV 文件 API
提议对 Python 进行此添加的 Python 增强提案。


13.1.1. 模块内容

csv 模块定义了以下函数:

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 版更改: 解析器现在对多行引用字段更加严格。 以前,如果一行在带引号的字段内结束而没有终止换行符,则会在返回的字段中插入换行符。 在读取字段中包含回车符的文件时,此行为会导致问题。 行为已更改为在不插入换行符的情况下返回字段。 因此,如果嵌入在字段中的换行符很重要,则应以保留换行符的方式将输入拆分为行。

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 必须是字符串或 Unicode 对象。 可以通过传递 Dialect 的子类或通过 fmtparams 关键字参数或两者来指定方言,并使用关键字参数覆盖方言的参数。 有关方言和格式参数的完整详细信息,请参阅 方言和格式参数 部分。
csv.unregister_dialect(name)
从方言注册表中删除与 name 关联的方言。 如果 name 不是已注册的方言名称,则会引发 Error。
csv.get_dialect(name)

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

2.5 版更改: 此函数现在返回不可变的 方言 。 以前返回了请求方言的实例。 用户可以修改底层类,改变活跃读者和作者的行为。

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

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

2.5 版中的新功能。

csv 模块定义了以下类:

class csv.DictReader(f, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds)

创建一个对象,它的操作类似于常规阅读器,但将读取的信息映射到字典中,其键由可选的 fieldnames 参数给出。 fieldnames 参数是一个 sequence,其元素按顺序与输入数据的字段相关联。 这些元素成为结果字典的键。 如果省略 fieldnames 参数,则将使用文件 f 第一行中的值作为字段名。 如果读取的行的字段数多于字段名序列,则剩余的数据将作为由 restkey 的值键控的序列添加。 如果读取的行的字段少于 fieldnames 序列,则其余键采用可选 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)

创建一个对象,其操作类似于常规编写器,但将字典映射到输出行。 fieldnames 参数是键的 序列,用于标识传递给 writerow() 方法的字典中的值写入文件 f[ X183X]。 可选的 restval 参数指定在字典缺少 fieldnames 中的键时要写入的值。 如果传递给 writerow() 方法的字典包含在 fieldnames 中找不到的键,则可选的 extrasaction 参数指示要采取的操作。 如果设置为 'raise',则会升高 ValueError。 如果设置为 'ignore',则字典中的额外值将被忽略。 任何其他可选或关键字参数都传递给底层 writer 实例。

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

一个简短的用法示例:

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 类是一个主要依赖于其属性的容器类,用于定义特定 reader 或 writer 实例的参数。
class csv.excel
excel 类定义了 Excel 生成的 CSV 文件的常用属性。 它以方言名称 'excel' 注册。
class csv.excel_tab
excel_tab 类定义 Excel 生成的制表符分隔文件的常用属性。 它以方言名称 'excel-tab' 注册。
class csv.Sniffer

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

Sniffer 类提供了两种方法:

sniff(sample, delimiters=None)

分析给定的 sample 并返回反映找到的参数的 Dialect 子类。 如果给出了可选的 delimiters 参数,则它被解释为包含可能的有效分隔符的字符串。

has_header(sample)

分析示例文本(假定为 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 对象引用所有非数字字段。

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

csv.QUOTE_NONE

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

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

csv 模块定义了以下异常:

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


13.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.skipinitialspace
当 True 时,紧跟在 定界符 之后的空格将被忽略。 默认值为 False。
Dialect.strict
当 True 时,在错误的 CSV 输入上引发异常 Error。 默认值为 False。


13.1.3. 读者对象

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

csvreader.next()
以列表形式返回 reader 的可迭代对象的下一行,根据当前方言进行解析。

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

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

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

2.5 版中的新功能。

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

csvreader.fieldnames

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

在 2.6 版中更改。


13.1.4. 写入器对象

Writer 对象(DictWriter 实例和 writer() 函数返回的对象)具有以下公共方法。 row 必须是 Writer 对象的字符串或数字序列和将字段名映射到字符串或数字的字典(首先通过 str() 传递它们) DictWriter 对象。 请注意,写出的复数被括号括起来。 这可能会导致其他读取 CSV 文件的程序出现问题(假设它们完全支持复数)。

csvwriter.writerow(row)
将 row 参数写入编写器的文件对象,根据当前方言进行格式化。
csvwriter.writerows(rows)
将 rows(如上所述的 row 对象的迭代)中的所有元素写入编写器的文件对象,根据当前方言进行格式化。

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

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

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

DictWriter.writeheader()

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

2.7 版中的新功能。


13.1.5. 例子

读取 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-bit-clean 保存一些 ASCII NUL 字符的问题。 因此,您可以编写函数或类来为您处理编码和解码,只要您避免使用 NUL 的 UTF-16 等编码。 建议使用 UTF-8。

下面的 unicode_csv_reader() 是一个 generator,它包装了 csv.reader 来处理 Unicode CSV 数据(Unicode 字符串列表)。 utf_8_encoder() 是一个 生成器 ,它将 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')

对于所有其他编码,可以使用以下 UnicodeReader 和 UnicodeWriter 类。 他们在构造函数中使用额外的 encoding 参数,并确保数据通过编码为 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)