Python 处理 CSV
一、关于CSV文件
CSV 文件,即逗号分隔值文件(Comma-Separated Values,CSV)。和 json 一样,CSV 是一种使用纯文本来储存数据的文件。在 CSV 文件中,一行就是一组数据,类似于 SQL 中的一行就是一条记录。一行中的每一个数据之间用逗号隔开,和 SQL 一样,这些被隔开的数据被称为字段。当然分隔符也可以不是逗号,并没有严格的规范。
下面是 csv 文件的使用规范,该规范不是严格的规范。
(1)使用 CRLF 换行
默认使用 CRLF 方式换行,也就是 Windows 系统默认使用的换行方式,其本质是一个\r加一个\n
aaa,bbb,ccc 'CRLF'
zzz,yyy,xxx 'CRLF'
写上'CRLF'是为了便于理解,实际文件中并没有'CRLF'
同时文件的最后一行结尾可以省略换行符
(2)第一行可做标题
第一行可以存在标题,格式和普通记录行的格式一样。标题要包含文件记录字段对应的名称,并且有和记录字段一样的数量。
name_1,name_2,name_3 'CRLF'
aaa,bbb,ccc 'CRLF'
zzz,yyy,xxx 'CRLF'
(3)使用双引号
每个数据都可以用双引号包裹起来,也可以不包裹。并且当数据中含有回车或换行符时,必须使用双引号包裹。
"aaa","b CRLF bb","ccc" 'CRLF'
zzz,yyy,xxx
另外,如果数据中要出现双引号,则应该在其前面再额外加一个双引号充当转义符。
"aaa","b""bb","ccc"
(4)每一行字段个数
每一行上的字段个数都必须是一样的,而且空格也会被视为数据。如果一个字段不想存储任何数据,就连续打上两个逗号。
aaa,,ccc
二、Python 处理 CSV 文件
Python 3.8 的 csv 模块的官方文档:https://docs.python.org/zh-cn/3.8/library/csv.html
Python 使用csv模块解析一个 csv 文件。因为 csv 文件标准不统一,因此 Python 为csv模块适配了不同的 csv 变种(dialect),甚至还允许自定义变种(这个过程被称为:在注册表中注册自定义的变种,这里注册表指的是 csv 模块中存储变种的对象)。比如通过 Excel 可以导出的 csv,csv模块内置了对其适配的解析方式。

1. csv 模块的函数
(1)reader 函数
csv.reader(csvfile, dialect='excel', **fmtparams)
该函数用来读取一个 csv 格式的文件或字符串,返回一个reader对象。
参数含义:
csvfile:用open函数打开的 csv 文件或 csv 格式的一个多行字符串。注意:必须设置
open函数的参数newline=''
dialect:指明使用的变种,例子中指定的是 Excel 的变种。
**fmtparams:用于指定使用的格式参数,使用例见下,详见格式参数一节
>>> import csv
>>> with open('eggs.csv', newline='') 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)writer 函数
该函数用来向一个 csv 文件写入数据,返回一个writer对象。
csv.writer(csvfile, dialect='excel', **fmtparams)
写入的每一条记录中,每一个值都只能是字符串类型。
参数和reader函数一样。
import csv
with open('eggs.csv', 'w', newline='') 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'])
(3)其他函数
csv.field_size_limit([new_limit])
# 不指定参数时返回解释器支持的最大字段长,指定了参数就修改解释器支持的最大字段长
"""--------下面的函数都与注册变种有关--------"""
csv.register_dialect(name[, dialect[, **fmtparams]])
# 注册一个变种,name 是变种名,dialect 是受支持的或自定义的变种
csv.unregister_dialect(name)
# 删除 name 对应变种的注册
csv.get_dialect(name)
# 返回 name 对应的变种
csv.list_dialects()
# 返回一个列表,包含所有已经注册的变种
(4)Reader 和 Writer 对象
Reader 和 Writer 对象分别是reader()和writer()的返回对象。
A. Reader
Reader 对象可以使用以下属性或方法
-
csvreader.
__next__():存在这个方法,则说明 Reader 对象可以直接作为迭代器使用。既可以直接调用next()函数一个一个的输出,也可以使用循环迭代输出。
import csv
csv_file = open('D:/test.csv', 'r', newline='', encoding='utf-8')
reader = csv.reader(csv_file)
title = next(reader) # 读取文档首行字段
print(title)
for i in reader:
print(i)
csv_file.close()
"""
结果
['Number', 'Name', 'Job']
['1', 'Bob', 'Soldier']
['2', 'Smith', 'Farmer']
['3', 'Alice', 'Teacher']
"""
csvreader.
dialect:当前使用的变种名csvreader.
line_num:返回已经读取了多少行csvreader.
fieldnames:返回当前文档使用的字段名(以列表的形式)
B. Writer
用于向文件中写入记录的对象,它的内容必须是字符串,其他数据类型需要使用str()转换。
Writer 对象可以使用以下对象和方法
-
csvwriter.
writerow(row):row 是一个字符串,相当于一条记录,将其写入到文件中(按照open()函数的打开方式决定写入的方式) -
csvwriter.
writerows(rows):rows 是一个列表或元组,内含多个字符串,相当于多条记录,将其写入到文件中(按照open()函数的打开方式决定写入的方式) -
DictWriter.
writeheader():写入首行字段,详见DictWriter类一节 -
csvwriter.
dialect:返回当前使用的 csv 变种
2. csv 模块的类
csv 模块定义了很多类,其中 DictReader 和 DictWriter 类是最主要的。
(1)DictReader 类
DictReader对象与reader()函数返回的 reader 对象差不多,用 reader 对象实现,但它更高级。它会将每一条记录与第一行规定的字段名(如果第一行有这样的规定)与值一一对应,放进一个字典里。
class csv.DictReader(f, fieldnames=None, restkey=None, restval=None,
dialect='excel', *args, **kwds)
参数含义:
f:打开的 csv 文件或 csv 格式的字符串fieldnames:一个列表或元组,内涵该 csv 文件每一个字段的字段名。如果不指定,该对象会默认将 csv 文件的第一行当成字段名,不论是不是对的。restkey/val:容错时指定默认值用的,详见官方文档- 其他:不具详表
看下面使用示例,现在有一个 test.csv 文件如下
Number,Name,Job
1,Bob,Soldier
2,Smith,Farmer
3,Alice,Teacher
使用下面 Python 代码读取并打印
import csv
csv_file = open('test.csv', 'r', newline='', encoding='utf-8')
dict_reader = csv.DictReader(csv_file)
for i in dict_reader:
print(i['Number'] +' '+ i['Name'] +' '+ i['Job'])
csv_file.close()
"""
结果如下
1 Bob Soldier
2 Smith Farmer
3 Alice Teacher
"""
(2)DictWriter 类
DictWriter 类用 writer 对象实现,但做了改进。使用字典的格式,而非字符串的格式向文件中写入记录。
class csv.DictWriter(f, fieldnames, restval='', extrasaction='raise',
dialect='excel', *args, **kwds)
参数含义与 DictReader 类相似。但注意,对于 DictWriter 类来说,参数fieldnames是必须写上的。
with open('names.csv', 'w', newline='') 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'})
3. csv 模块的常量
In [1]: import csv
# 指示 writer 对象仅为包含特殊字符(如定界符、数据内引号或结束符)的字段加上引号
In [2]: csv.QUOTE_MINIMAL
Out[2]: 0
# 指示 writer 对象给所有字段加上引号
In [3]: csv.QUOTE_ALL
Out[3]: 1
# 指示 writer 为所有非数字字段加引号
# 指示 reader 将所有未用引号包含的字段转为 float 型
In [4]: csv.QUOTE_NONNUMERIC
Out[4]: 2
# 指示 writer 不使用引号包含字段。当定界符出现在输出数据中时,其前面应该有转义符
# 指示 reader 不对引号字符进行特殊处理
In [5]: csv.QUOTE_NONE
Out[5]: 3
4. 变种与格式参数
(1)Dialect 类
csv 模块中的 Dialect 类负责封装管理变种。它支持以下属性
-
Dialect.
delimiter:用于分隔字段的单字符,默认为','。 -
Dialect.
doublequote:为 true 时(默认)使用双重双引号来转义出现在数据中的双引号;为 false 时,使用Dialect.escapechar属性规定的字符充当转义符。该属性用于写入过程,对读取过程无效。 -
Dialect.
escapechar:单个字符,用于规定向文件写入时用什么字符充当转义符。 -
Dialect.
lineterminator:规定换行符,默认\r\n。 -
Dialect.
quotechar:一个单字符(默认为双引号),用于包住含有特殊字符的字段,特殊字符如定界符,数据内的双引号或换行符。 -
Dialect.
quoting:控制 writer 何时生成引号,以及 reader 何时识别引号。该属性可以等于任何 QUOTE_* 常量(参见 模块内容 段落),默认为 QUOTE_MINIMAL。 -
Dialect.
skipinitialspace:如果为 True,则忽略定界符之后的空格。默认值为 False。 -
Dialect.
strict:如果为 True,则在输入错误的 CSV 时抛出 Error 异常。默认值为 False。
(2)自定义变种
import csv
# 在这里,变种名为 unixpwd,定界符为冒号,并常量通过 QUOTE_NONE 指定行为
csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)
with open('passwd', newline='') as f:
reader = csv.reader(f, 'unixpwd')