Python 处理 CSV

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模块内置了对其适配的解析方式。

Excel是可以导出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')
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342