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 模块的 readerwriter 对象读取和写入序列。 程序员还可以使用 DictReaderDictWriter 类以字典形式读取和写入数据。

笔记

此版本的 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 类不同,DictWriterfieldnames 参数不是可选的。 由于 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 类是一个主要依赖于其属性的容器类,用于定义特定 readerwriter 实例的参数。
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 对象仅引用包含特殊字符的字段,例如 delimiterquotecharlineterminator 中的任何字符。
csv.QUOTE_NONNUMERIC

指示 writer 对象引用所有非数字字段。

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

csv.QUOTE_NONE

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

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

csv 模块定义了以下异常:

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


13.1.2. 方言和格式参数

为了更容易地指定输入和输出记录的格式,特定的格式参数被组合到方言中。 方言是 Dialect 类的子类,具有一组特定方法和一个 validate() 方法。 在创建 readerwriter 对象时,程序员可以指定一个字符串或 Dialect 类的子类作为方言参数。 除了或代替 dialect 参数,程序员还可以指定单独的格式化参数,这些参数与下面为 Dialect 类定义的属性具有相同的名称。

方言支持以下属性:

Dialect.delimiter
用于分隔字段的单字符字符串。 默认为 ','
Dialect.doublequote

控制如何引用字段内出现的 quotechar 实例本身。 当True时,字符加倍。 当 False 时,escapechar 用作 quotechar 的前缀。 默认为 True

在输出时,如果 doublequoteFalse 并且没有设置 escapechar,如果 quotecharError在一个领域找到。

Dialect.escapechar
如果 quoting 设置为 QUOTE_NONEquotechar 如果 双引号。 读取时,escapechar 会删除以下字符的任何特殊含义。 它默认为 None,禁用转义。
Dialect.lineterminator

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

笔记

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

Dialect.quotechar
用于引用包含特殊字符(例如 delimiterquotechar)或包含换行符的字段的单字符字符串。 默认为 '"'
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')

对于所有其他编码,可以使用以下 UnicodeReaderUnicodeWriter 类。 他们在构造函数中使用额外的 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)