Python 處理 CSV

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ì)其適配的解析方式。

Excel是可以導(dǎo)出csv文件的

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')
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市尔当,隨后出現(xiàn)的幾起案子莲祸,更是在濱河造成了極大的恐慌,老刑警劉巖椭迎,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锐帜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡畜号,警方通過查閱死者的電腦和手機(jī)缴阎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來简软,“玉大人蛮拔,你說我怎么就攤上這事√娑觯” “怎么了语泽?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)视卢。 經(jīng)常有香客問我踱卵,道長(zhǎng),這世上最難降的妖魔是什么据过? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任惋砂,我火速辦了婚禮,結(jié)果婚禮上绳锅,老公的妹妹穿的比我還像新娘西饵。我一直安慰自己,他們只是感情好鳞芙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布眷柔。 她就那樣靜靜地躺著期虾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪驯嘱。 梳的紋絲不亂的頭發(fā)上镶苞,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音鞠评,去河邊找鬼茂蚓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛剃幌,可吹牛的內(nèi)容都是我干的聋涨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼负乡,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼牍白!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起敬鬓,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤淹朋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后钉答,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體础芍,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年数尿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了仑性。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡右蹦,死狀恐怖诊杆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情何陆,我是刑警寧澤晨汹,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站贷盲,受9級(jí)特大地震影響淘这,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜巩剖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一铝穷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧佳魔,春花似錦曙聂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)断国。三九已至,卻和暖如春朦佩,著一層夾襖步出監(jiān)牢的瞬間并思,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工语稠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人弄砍。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓仙畦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親音婶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子慨畸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355