13.1. csv
— CSV 文件读写¶
2.3 新版功能.
The so-called CSV (Comma Separated Values) format is the most common import and export format for spreadsheets and databases. There is no “CSV standard”, so the format is operationally defined by the many applications which read and write it. The lack of a standard means that subtle differences often exist in the data produced and consumed by different applications. These differences can make it annoying to process CSV files from multiple sources. Still, while the delimiters and quoting characters vary, the overall format is similar enough that it is possible to write a single module which can efficiently manipulate such data, hiding the details of reading and writing the data from the programmer.
The csv
module implements classes to read and write tabular data in CSV
format. It allows programmers to say, “write this data in the format preferred
by Excel,” or “read data from this file which was generated by Excel,” without
knowing the precise details of the CSV format used by Excel. Programmers can
also describe the CSV formats understood by other applications or define their
own special-purpose CSV formats.
csv
模块中的 reader
类和 writer
类可用于读写序列化的数据。也可使用 DictReader
类和 DictWriter
类以字典的形式读写数据。
注解
This version of the csv
module doesn’t support Unicode input. Also,
there are currently some issues regarding ASCII NUL characters. Accordingly,
all input should be UTF-8 or printable ASCII to be safe; see the examples in
section 例子.
参见
- 该实现在“Python 增强提议” - PEP 305 (CSV 文件 API) 中被提出
《Python 增强提议》提出了对 Python 的这一补充。
13.1.1. 模块内容¶
csv
模块定义了以下函数:
-
csv.
reader
(csvfile, dialect='excel', **fmtparams)¶ Return a reader object which will iterate over lines in the given csvfile. csvfile can be any object which supports the iterator protocol and returns a string each time its
next()
method is called — file objects and list objects are both suitable. If csvfile is a file object, it must be opened with the ‘b’ flag on platforms where that makes a difference. An optional dialect parameter can be given which is used to define a set of parameters specific to a particular CSV dialect. It may be an instance of a subclass of theDialect
class or one of the strings returned by thelist_dialects()
function. The other optional fmtparams keyword arguments can be given to override individual formatting parameters in the current dialect. For full details about the dialect and formatting parameters, see section 变种与格式参数.Each row read from the csv file is returned as a list of strings. No automatic data type conversion is performed.
一个简短的用法示例:
>>> 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 版更改: The parser is now stricter with respect to multi-line quoted fields. Previously, if a line ended within a quoted field without a terminating newline character, a newline would be inserted into the returned field. This behavior caused problems when reading files which contained carriage return characters within fields. The behavior was changed to return the field without inserting newlines. As a consequence, if newlines embedded within fields are important, the input should be split into lines in a manner which preserves the newline characters.
-
csv.
writer
(csvfile, dialect='excel', **fmtparams)¶ Return a writer object responsible for converting the user’s data into delimited strings on the given file-like object. csvfile can be any object with a
write()
method. If csvfile is a file object, it must be opened with the ‘b’ flag on platforms where that makes a difference. An optional dialect parameter can be given which is used to define a set of parameters specific to a particular CSV dialect. It may be an instance of a subclass of theDialect
class or one of the strings returned by thelist_dialects()
function. The other optional fmtparams keyword arguments can be given to override individual formatting parameters in the current dialect. For full details about the dialect and formatting parameters, see section 变种与格式参数. To make it as easy as possible to interface with modules which implement the DB API, the valueNone
is written as the empty string. While this isn’t a reversible transformation, it makes it easier to dump SQL NULL data values to CSV files without preprocessing the data returned from acursor.fetch*
call. Floats are stringified withrepr()
before being written. All other non-string data are stringified withstr()
before being written.一个简短的用法示例:
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)¶ Associate dialect with name. name must be a string or Unicode object. The dialect can be specified either by passing a sub-class of
Dialect
, or by fmtparams keyword arguments, or both, with keyword arguments overriding parameters of the dialect. For full details about the dialect and formatting parameters, see section 变种与格式参数.
-
csv.
get_dialect
(name)¶ Return the dialect associated with name. An
Error
is raised if name is not a registered dialect name.在 2.5 版更改: This function now returns an immutable
Dialect
. Previously an instance of the requested dialect was returned. Users could modify the underlying class, changing the behavior of active readers and writers.
-
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)¶ Create an object which operates like a regular reader but maps the information read into a dict whose keys are given by the optional fieldnames parameter. The fieldnames parameter is a sequence whose elements are associated with the fields of the input data in order. These elements become the keys of the resulting dictionary. If the fieldnames parameter is omitted, the values in the first row of the file f will be used as the fieldnames. If the row read has more fields than the fieldnames sequence, the remaining data is added as a sequence keyed by the value of restkey. If the row read has fewer fields than the fieldnames sequence, the remaining keys take the value of the optional restval parameter. Any other optional or keyword arguments are passed to the underlying
reader
instance.一个简短的用法示例:
>>> 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)¶ Create an object which operates like a regular writer but maps dictionaries onto output rows. The fieldnames parameter is a sequence of keys that identify the order in which values in the dictionary passed to the
writerow()
method are written to the file f. The optional restval parameter specifies the value to be written if the dictionary is missing a key in fieldnames. If the dictionary passed to thewriterow()
method contains a key not found in fieldnames, the optional extrasaction parameter indicates what action to take. If it is set to'raise'
aValueError
is raised. If it is set to'ignore'
, extra values in the dictionary are ignored. Any other optional or keyword arguments are passed to the underlyingwriter
instance.Note that unlike the
DictReader
class, the fieldnames parameter of theDictWriter
is not optional. Since Python’sdict
objects are not ordered, there is not enough information available to deduce the order in which the row should be written to the file 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.
Sniffer
¶ Sniffer
类用于推断 CSV 文件的格式。Sniffer
类提供了两个方法:
使用 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_NONE
¶ 指示
writer
对象不使用引号引出字段。当 定界符 出现在输出数据中时,其前面应该有 转义符。如果未设置 转义符,则遇到任何需要转义的字符时,writer 都会抛出Error
异常。指示
reader
不对引号字符进行特殊处理。
csv
模块定义了以下异常:
-
exception
csv.
Error
¶ 该异常可能由任何发生错误的函数抛出。
13.1.2. 变种与格式参数¶
为了更容易指定输入和输出记录的格式,特定的一组格式参数组合为一个 dialect(变种)。一个 dialect 是一个 Dialect
类的子类,它具有一组特定的方法和一个 validate()
方法。创建 reader
或 writer
对象时,程序员可以将某个字符串或 Dialect
类的子类指定为 dialect 参数。要想补充或覆盖 dialect 参数,程序员还可以单独指定某些格式参数,这些参数的名称与下面 Dialect
类定义的属性相同。
Dialect 类支持以下属性:
-
Dialect.
delimiter
¶ 一个用于分隔字段的单字符,默认为
','
。
-
Dialect.
doublequote
¶ 控制出现在字段中的 引号字符 本身应如何被引出。当该属性为
True
时,双写引号字符。如果该属性为False
,则在 引号字符 的前面放置 转义符。默认值为True
。在输出时,如果 doublequote 是
False
,且 转义符 未指定,且在字段中发现 引号字符 时,会抛出Error
异常。
-
Dialect.
escapechar
¶ 一个用于 writer 的单字符,用来在 quoting 设置为
QUOTE_NONE
的情况下转义 定界符,在 doublequote 设置为False
的情况下转义 引号字符。在读取时,escapechar 去除了其后所跟字符的任何特殊含义。该属性默认为None
,表示禁用转义。
-
Dialect.
lineterminator
¶ 放在
writer
产生的行的结尾,默认为'\r\n'
。注解
reader
经过硬编码,会识别'\r'
或'\n'
作为行尾,并忽略 lineterminator。未来可能会更改这一行为。
-
Dialect.
quotechar
¶ 一个单字符,用于包住含有特殊字符的字段,特殊字符如 定界符 或 引号字符 或换行符。默认为
'"'
。
-
Dialect.
quoting
¶ 控制 writer 何时生成引号,以及 reader 何时识别引号。该属性可以等于任何
QUOTE_*
常量(参见 模块内容 段落),默认为QUOTE_MINIMAL
。
13.1.3. Reader 对象¶
Reader 对象(DictReader
实例和 reader()
函数返回的对象)具有以下公开方法:
-
csvreader.
next
()¶ Return the next row of the reader’s iterable object as a list, parsed according to the current dialect.
Reader 对象具有以下公开属性:
-
csvreader.
dialect
¶ 变种描述,只读,供解析器使用。
-
csvreader.
line_num
¶ 源迭代器已经读取了的行数。它与返回的记录数不同,因为记录可能跨越多行。
2.5 新版功能.
DictReader 对象具有以下公开属性:
-
csvreader.
fieldnames
¶ 字段名称。如果在创建对象时未传入字段名称,则首次访问时或从文件中读取第一条记录时会初始化此属性。
在 2.6 版更改.
13.1.4. Writer 对象¶
Writer
objects (DictWriter
instances and objects returned by
the writer()
function) have the following public methods. A row must be
a sequence of strings or numbers for Writer
objects and a dictionary
mapping fieldnames to strings or numbers (by passing them through str()
first) for DictWriter
objects. Note that complex numbers are written
out surrounded by parens. This may cause some problems for other programs which
read CSV files (assuming they support complex numbers at all).
-
csvwriter.
writerow
(row)¶ 将 row 形参写入 writer 的文件对象,并按照当前设定形式进行格式化。
-
csvwriter.
writerows
(rows)¶ 将 rows*(即能迭代出多个上述 *row 对象的迭代器)中的所有元素写入 writer 的文件对象,并根据当前设置的变种进行格式化。
Writer 对象具有以下公开属性:
-
csvwriter.
dialect
¶ 变种描述,只读,供 writer 使用。
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')
Reader 的更高级用法——捕获并报告错误:
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
The csv
module doesn’t directly support reading and writing Unicode, but
it is 8-bit-clean save for some problems with ASCII NUL characters. So you can
write functions or classes that handle the encoding and decoding for you as long
as you avoid encodings like UTF-16 that use NULs. UTF-8 is recommended.
unicode_csv_reader()
below is a generator that wraps csv.reader
to handle Unicode CSV data (a list of Unicode strings). utf_8_encoder()
is a generator that encodes the Unicode strings as UTF-8, one string (or row) at
a time. The encoded strings are parsed by the CSV reader, and
unicode_csv_reader()
decodes the UTF-8-encoded cells back into 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')
For all other encodings the following UnicodeReader
and
UnicodeWriter
classes can be used. They take an additional encoding
parameter in their constructor and make sure that the data passes the real
reader or writer encoded as 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)