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提出了这个补充。

1.模块内容

csv模块定义了以下功能:

csv.reader(csvfile, dialect='excel', **fmtparams)

返回将在给定的csv文件中遍历行的reader对象。csvfile可以是任何支持迭代器协议的对象,每次next()调用它的方法时都会返回一个字符串- 文件对象和列表对象都适用。如果csvfile是一个文件对象,那么它必须在平台上用“b”标志打开,这是有所作为的。可以给出可选的方言参数,该参数用于定义特定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)

返回一个编写器对象,负责将用户的数据转换为给定类文件对象上的分隔字符串。csvfile可以是具有write()方法的任何对象。如果csvfile是一个文件对象,那么它必须在平台上用“b”标志打开,这是有所作为的。可以给出可选的方言参数,该参数用于定义特定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)

方言名字联系起来名称必须是字符串或Unicode对象。方言可以通过传递子类Dialectfmtparams关键字参数或两者来指定,其中关键字参数覆盖方言的参数。有关方言和格式参数的完整详细信息,请参见方言和格式参数一节。

csv.unregister_dialect(name)

从方言注册表中删除与姓名关联的方言。Error如果名称不是已注册的方言名称,则引发An 。

csv.get_dialect(name)

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

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

csv.list_dialects()

返回所有注册方言的名称。

csv.field_size_limit([new_limit])

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

2.5版本中的新功能。

csv模块定义了以下类:

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

创建一个像普通阅读器一样运行的对象,但将读取的信息映射到由可选fieldnames参数提供的键的字典中。的字段名的参数是,其元件与所述输入数据的顺序中的字段相关联的序列。这些元素成为最终字典的关键。如果省略fieldnames参数,则csvfile的第一行中的将用作字段名称。如果行读取的字段数多于字段名称序列,则剩余的数据将作为由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(csvfile, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwds)

创建一个像普通作家一样操作的对象,但将字典映射到输出行。该字段名参数是标识在其中在传递给字典值的顺序键的序列writerow()的方法被写入到csvfile。可选的restval参数指定字典在字段名称中缺少键时要写入的值。如果传递给writerow()方法的字典包含在字段名中找不到的键,则可选的extrasaction参数指示要执行的操作。如果它被设置为'raise'一个ValueError提高。如果它设置为'ignore',字典中的额外值将被忽略。任何其他可选参数或关键字参数都会传递给底层writer实例。

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

一个简短的用法示例:

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)

分析给定的样本并返回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对象只引用那些包含特殊字符,如字段分隔符quotechar或任何字符lineterminator

csv.QUOTE_NONNUMERIC

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

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

csv.QUOTE_NONE

指示writer对象永远不会引用字段。当输出数据中出现当前分隔符时,它前面是当前的escapechar字符。如果没有设置escapecharError那么如果遇到任何需要转义的字符,作者将会提出。

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

csv模块定义了以下例外情况:

exception csv.Error

当检测到错误时由任何功能引发。

2.方言和格式参数

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

方言支持以下属性:

Dialect.delimiter

用于分隔字段的单字符字符串。它默认为','

Dialect.doublequote

控制出现在字段内部的quotechar实例应如何引用。何时True,角色加倍。当False时,escapechar作为前缀quotechar。它默认为True

在输出时,如果双引号False没有escapechar设置,Error如果需要进行上调quotechar是在现场发现的。

Dialect.escapechar

由作家使用的一个字符串转换为逃避分隔符,如果报价被设置为QUOTE_NONEquotechar如果双引号False。阅读时,escapechar从下列字符中删除任何特殊含义。它默认为None禁用转义。

Dialect.lineterminator

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

注意

reader是硬编码识别任一'\r''\n'作为行结束,并忽略lineterminator。这种行为在未来可能会改变。

Dialect.quotechar

一个字符的字符串,用于引用包含特殊字符(如分隔符引号)或包含换行符的字段。它默认为'"'

Dialect.quoting

控制引号应由作者生成并由读者识别。它可以采用任何QUOTE_*常量(请参见模块内容部分),并且默认为QUOTE_MINIMAL

Dialect.skipinitialspace

True,忽略分隔符后面的空格。默认是False

Dialect.strict

什么时候出现错误的CSV输入True异常Error。默认是False

3.阅读器对象

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

csvreader.next()

将读者的可迭代对象的下一行作为列表返回,根据当前的方言进行解析。

读者对象具有以下公共属性:

csvreader.dialect

解析器使用的方言的只读描述。

csvreader.line_num

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

2.5版本中的新功能。

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

csvreader.fieldnames

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

在版本2.6中更改。

4.作家对象

Writer对象(DictWriterwriter()函数返回的实例和对象)具有以下公共方法。甲必须是字符串或数字为序列Writer对象和一个字典映射字段名到字符串或数字(通过使它们通过str()第一)为DictWriter对象。请注意,复数数字是由parens包围的。这可能会导致读取CSV文件的其他程序出现问题(假设它们完全支持复数)。

csvwriter.writerow(row)

参数写入作者的文件对象,根据当前的方言格式化。

csvwriter.writerows(rows)

将所有参数(如上所述的对象列表)写入作者的文件对象,根据当前的方言格式化。

编写器对象具有以下公共属性:

csvwriter.dialect

作者正在使用的方言的只读说明。

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

DictWriter.writeheader()

用字段名写一行(如构造函数中指定的那样)。

2.7版本的新功能。

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位清除的,用于存储ASCII NUL字符的一些问题。因此,只要避免使用NUL的UTF-16编码,就可以编写处理编码和解码的函数或类。建议使用UTF-8。

unicode_csv_reader()下面是一个生成器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类。他们在构造函数中使用额外的编码参数,并确保数据通过编码为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)

扫码关注云+社区

领取腾讯云代金券