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')