Python 處理 CSV
一压汪、關(guān)于CSV文件
CSV 文件粪牲,即逗號(hào)分隔值文件(Comma-Separated Values,CSV)止剖。和 json 一樣腺阳,CSV 是一種使用純文本來儲(chǔ)存數(shù)據(jù)的文件。在 CSV 文件中穿香,一行就是一組數(shù)據(jù)亭引,類似于 SQL 中的一行就是一條記錄。一行中的每一個(gè)數(shù)據(jù)之間用逗號(hào)隔開皮获,和 SQL 一樣焙蚓,這些被隔開的數(shù)據(jù)被稱為字段。當(dāng)然分隔符也可以不是逗號(hào)洒宝,并沒有嚴(yán)格的規(guī)范购公。
下面是 csv 文件的使用規(guī)范,該規(guī)范不是嚴(yán)格的規(guī)范雁歌。
(1)使用 CRLF 換行
默認(rèn)使用 CRLF 方式換行宏浩,也就是 Windows 系統(tǒng)默認(rèn)使用的換行方式,其本質(zhì)是一個(gè)\r
加一個(gè)\n
aaa,bbb,ccc 'CRLF'
zzz,yyy,xxx 'CRLF'
寫上'CRLF'是為了便于理解靠瞎,實(shí)際文件中并沒有'CRLF'
同時(shí)文件的最后一行結(jié)尾可以省略換行符
(2)第一行可做標(biāo)題
第一行可以存在標(biāo)題比庄,格式和普通記錄行的格式一樣。標(biāo)題要包含文件記錄字段對(duì)應(yīng)的名稱乏盐,并且有和記錄字段一樣的數(shù)量佳窑。
name_1,name_2,name_3 'CRLF'
aaa,bbb,ccc 'CRLF'
zzz,yyy,xxx 'CRLF'
(3)使用雙引號(hào)
每個(gè)數(shù)據(jù)都可以用雙引號(hào)包裹起來,也可以不包裹丑勤。并且當(dāng)數(shù)據(jù)中含有回車或換行符時(shí)华嘹,必須使用雙引號(hào)包裹。
"aaa","b CRLF bb","ccc" 'CRLF'
zzz,yyy,xxx
另外法竞,如果數(shù)據(jù)中要出現(xiàn)雙引號(hào),則應(yīng)該在其前面再額外加一個(gè)雙引號(hào)充當(dāng)轉(zhuǎn)義符强挫。
"aaa","b""bb","ccc"
(4)每一行字段個(gè)數(shù)
每一行上的字段個(gè)數(shù)都必須是一樣的岔霸,而且空格也會(huì)被視為數(shù)據(jù)。如果一個(gè)字段不想存儲(chǔ)任何數(shù)據(jù)俯渤,就連續(xù)打上兩個(gè)逗號(hào)呆细。
aaa,,ccc
二、Python 處理 CSV 文件
Python 3.8 的 csv 模塊的官方文檔:https://docs.python.org/zh-cn/3.8/library/csv.html
Python 使用csv
模塊解析一個(gè) csv 文件八匠。因?yàn)?csv 文件標(biāo)準(zhǔn)不統(tǒng)一絮爷,因此 Python 為csv
模塊適配了不同的 csv 變種(dialect)趴酣,甚至還允許自定義變種(這個(gè)過程被稱為:在注冊(cè)表中注冊(cè)自定義的變種,這里注冊(cè)表指的是 csv 模塊中存儲(chǔ)變種的對(duì)象)坑夯。比如通過 Excel 可以導(dǎo)出的 csv岖寞,csv
模塊內(nèi)置了對(duì)其適配的解析方式。
1. csv 模塊的函數(shù)
(1)reader 函數(shù)
csv.reader(csvfile, dialect='excel', **fmtparams)
該函數(shù)用來讀取一個(gè) csv 格式的文件或字符串柜蜈,返回一個(gè)reader
對(duì)象仗谆。
參數(shù)含義:
csvfile
:用open
函數(shù)打開的 csv 文件或 csv 格式的一個(gè)多行字符串。注意:必須設(shè)置
open
函數(shù)的參數(shù)newline=''
dialect
:指明使用的變種淑履,例子中指定的是 Excel 的變種隶垮。
**fmtparams
:用于指定使用的格式參數(shù),使用例見下秘噪,詳見格式參數(shù)一節(jié)
>>> 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 函數(shù)
該函數(shù)用來向一個(gè) csv 文件寫入數(shù)據(jù)狸吞,返回一個(gè)writer
對(duì)象。
csv.writer(csvfile, dialect='excel', **fmtparams)
寫入的每一條記錄中指煎,每一個(gè)值都只能是字符串類型蹋偏。
參數(shù)和reader
函數(shù)一樣。
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)其他函數(shù)
csv.field_size_limit([new_limit])
# 不指定參數(shù)時(shí)返回解釋器支持的最大字段長(zhǎng)贯要,指定了參數(shù)就修改解釋器支持的最大字段長(zhǎng)
"""--------下面的函數(shù)都與注冊(cè)變種有關(guān)--------"""
csv.register_dialect(name[, dialect[, **fmtparams]])
# 注冊(cè)一個(gè)變種暖侨,name 是變種名,dialect 是受支持的或自定義的變種
csv.unregister_dialect(name)
# 刪除 name 對(duì)應(yīng)變種的注冊(cè)
csv.get_dialect(name)
# 返回 name 對(duì)應(yīng)的變種
csv.list_dialects()
# 返回一個(gè)列表崇渗,包含所有已經(jīng)注冊(cè)的變種
(4)Reader 和 Writer 對(duì)象
Reader 和 Writer 對(duì)象分別是reader()
和writer()
的返回對(duì)象字逗。
A. Reader
Reader 對(duì)象可以使用以下屬性或方法
-
csvreader.
__next__()
:存在這個(gè)方法,則說明 Reader 對(duì)象可以直接作為迭代器使用宅广。既可以直接調(diào)用next()
函數(shù)一個(gè)一個(gè)的輸出葫掉,也可以使用循環(huán)迭代輸出。
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()
"""
結(jié)果
['Number', 'Name', 'Job']
['1', 'Bob', 'Soldier']
['2', 'Smith', 'Farmer']
['3', 'Alice', 'Teacher']
"""
csvreader.
dialect
:當(dāng)前使用的變種名csvreader.
line_num
:返回已經(jīng)讀取了多少行csvreader.
fieldnames
:返回當(dāng)前文檔使用的字段名(以列表的形式)
B. Writer
用于向文件中寫入記錄的對(duì)象跟狱,它的內(nèi)容必須是字符串俭厚,其他數(shù)據(jù)類型需要使用str()
轉(zhuǎn)換。
Writer 對(duì)象可以使用以下對(duì)象和方法
-
csvwriter.
writerow(row)
:row 是一個(gè)字符串驶臊,相當(dāng)于一條記錄挪挤,將其寫入到文件中(按照open()
函數(shù)的打開方式?jīng)Q定寫入的方式) -
csvwriter.
writerows(rows)
:rows 是一個(gè)列表或元組,內(nèi)含多個(gè)字符串关翎,相當(dāng)于多條記錄扛门,將其寫入到文件中(按照open()
函數(shù)的打開方式?jīng)Q定寫入的方式) -
DictWriter.
writeheader()
:寫入首行字段,詳見DictWriter
類一節(jié) -
csvwriter.
dialect
:返回當(dāng)前使用的 csv 變種
2. csv 模塊的類
csv 模塊定義了很多類纵寝,其中 DictReader 和 DictWriter 類是最主要的论寨。
(1)DictReader 類
DictReader
對(duì)象與reader()
函數(shù)返回的 reader 對(duì)象差不多,用 reader 對(duì)象實(shí)現(xiàn),但它更高級(jí)葬凳。它會(huì)將每一條記錄與第一行規(guī)定的字段名(如果第一行有這樣的規(guī)定)與值一一對(duì)應(yīng)绰垂,放進(jìn)一個(gè)字典里。
class csv.DictReader(f, fieldnames=None, restkey=None, restval=None,
dialect='excel', *args, **kwds)
參數(shù)含義:
f
:打開的 csv 文件或 csv 格式的字符串fieldnames
:一個(gè)列表或元組火焰,內(nèi)涵該 csv 文件每一個(gè)字段的字段名劲装。如果不指定,該對(duì)象會(huì)默認(rèn)將 csv 文件的第一行當(dāng)成字段名荐健,不論是不是對(duì)的酱畅。restkey/val
:容錯(cuò)時(shí)指定默認(rèn)值用的,詳見官方文檔- 其他:不具詳表
看下面使用示例江场,現(xiàn)在有一個(gè) 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()
"""
結(jié)果如下
1 Bob Soldier
2 Smith Farmer
3 Alice Teacher
"""
(2)DictWriter 類
DictWriter 類用 writer 對(duì)象實(shí)現(xiàn)纺酸,但做了改進(jìn)。使用字典的格式址否,而非字符串的格式向文件中寫入記錄餐蔬。
class csv.DictWriter(f, fieldnames, restval='', extrasaction='raise',
dialect='excel', *args, **kwds)
參數(shù)含義與 DictReader 類相似。但注意佑附,對(duì)于 DictWriter 類來說樊诺,參數(shù)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 對(duì)象僅為包含特殊字符(如定界符音同、數(shù)據(jù)內(nèi)引號(hào)或結(jié)束符)的字段加上引號(hào)
In [2]: csv.QUOTE_MINIMAL
Out[2]: 0
# 指示 writer 對(duì)象給所有字段加上引號(hào)
In [3]: csv.QUOTE_ALL
Out[3]: 1
# 指示 writer 為所有非數(shù)字字段加引號(hào)
# 指示 reader 將所有未用引號(hào)包含的字段轉(zhuǎn)為 float 型
In [4]: csv.QUOTE_NONNUMERIC
Out[4]: 2
# 指示 writer 不使用引號(hào)包含字段词爬。當(dāng)定界符出現(xiàn)在輸出數(shù)據(jù)中時(shí),其前面應(yīng)該有轉(zhuǎn)義符
# 指示 reader 不對(duì)引號(hào)字符進(jìn)行特殊處理
In [5]: csv.QUOTE_NONE
Out[5]: 3
4. 變種與格式參數(shù)
(1)Dialect 類
csv 模塊中的 Dialect 類負(fù)責(zé)封裝管理變種权均。它支持以下屬性
-
Dialect.
delimiter
:用于分隔字段的單字符顿膨,默認(rèn)為','
。 -
Dialect.
doublequote
:為 true 時(shí)(默認(rèn))使用雙重雙引號(hào)來轉(zhuǎn)義出現(xiàn)在數(shù)據(jù)中的雙引號(hào)叽赊;為 false 時(shí)恋沃,使用Dialect.escapechar
屬性規(guī)定的字符充當(dāng)轉(zhuǎn)義符。該屬性用于寫入過程必指,對(duì)讀取過程無(wú)效囊咏。 -
Dialect.
escapechar
:?jiǎn)蝹€(gè)字符,用于規(guī)定向文件寫入時(shí)用什么字符充當(dāng)轉(zhuǎn)義符塔橡。 -
Dialect.
lineterminator
:規(guī)定換行符梅割,默認(rèn)\r\n
。 -
Dialect.
quotechar
:一個(gè)單字符(默認(rèn)為雙引號(hào))葛家,用于包住含有特殊字符的字段炮捧,特殊字符如定界符,數(shù)據(jù)內(nèi)的雙引號(hào)或換行符惦银。 -
Dialect.
quoting
:控制 writer 何時(shí)生成引號(hào),以及 reader 何時(shí)識(shí)別引號(hào)。該屬性可以等于任何 QUOTE_* 常量(參見 模塊內(nèi)容 段落)扯俱,默認(rèn)為 QUOTE_MINIMAL书蚪。 -
Dialect.
skipinitialspace
:如果為 True,則忽略定界符之后的空格迅栅。默認(rèn)值為 False殊校。 -
Dialect.
strict
:如果為 True,則在輸入錯(cuò)誤的 CSV 時(shí)拋出 Error 異常读存。默認(rèn)值為 False为流。
(2)自定義變種
import csv
# 在這里,變種名為 unixpwd让簿,定界符為冒號(hào)敬察,并常量通過 QUOTE_NONE 指定行為
csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)
with open('passwd', newline='') as f:
reader = csv.reader(f, 'unixpwd')