Python 如何讀寫CSV 與合併CSV檔案. CSV是 ... - Medium

文章推薦指數: 80 %
投票人數:10人

要透過Python寫入資料並生成CSV檔案,一樣需要引入csv套件,並且建立writer物件來 ... 以七月份的銷售(sales07.csv)為例,檔案格式如下:欄位的標題 ... GetunlimitedaccessOpeninappHomeNotificationsListsStoriesWritePublishedinPythonEverywhere-fromBeginnertoAdvancedPython如何讀寫CSV與合併CSV檔案Koshimizu,Hokkaido,Japan,photobySeanYehCSV是「Comma-SeparatedValues」的縮寫,從名字就可以看出他是以逗號分隔的值。

與JSON一樣,CSV是純文字檔,其檔案以純文字形式儲存表格資料(數字和文字)。

「純文字」意味著該檔案是一個字元序列,不含必須像二進位數字那樣被解讀的資料。

因此,與Excel不同的是,CSV是一個簡易型的試算表,一行代表的就是試算表中的一列。

逗號分隔了該列的儲存格資料。

CSV中沒有型別的差異,一率都是字串,沒有字體大小或色彩的差異,也沒有儲存格寬度高度等的區別,沒有多個sheet的問題,沒有合併儲存格,也不能嵌入圖表或圖片物件。

從CSV檔案的特性可以看到,它的優點是簡單、輕量,可以使用一般的文字編輯器開啟。

目前廣泛的應用在程式之間轉移表格資料,例如公開資訊、網站或會計軟體等地方,都可以看到CSV的影子。

csv模組可以讓我們讀寫csv檔案,以下分別針對讀取與寫入說明如何使用這個模組。

讀取CSV要透過Python讀取CSV檔案,需要引入csv套件,並且開啟檔案建立reader物件,然後才可以使用for迴圈讀取資料。

下面依序進行介紹。

引入模組使用模組的第一步就是將模組引入到專案裡面。

使用csv模組之前,也需要引入專案。

importcsv建立reader物件引入之後,就可以開始使用csv模組。

要從CSV檔案裡面讀取資料,需要先建立一個reader物件。

file=open('data.csv')reader=csv.reader(file)file.close()如上面的程式碼,要先使用open函式來開啟檔案。

在這裡我們要開啟的是一個csv檔(data.csv,內容如下)。

檔案開啟後(指定給file變數),將返回的物件傳入csv的reader函式中(csv.reader(file))//data.csvusername,Id,first_name,last_namebooker33,1,Ana,Bookergreyc,2,LauraCindy,Greymike81,3,Mike,Johnsonmaryww,4,Mary,Willsmithj38,5,Jones,Smith接下來,我們直接將變數reader印出來看看,發現只能看到一個物件(<_csv.readerobjectat0x7fac90105050>)。

print(reader)這時候還需要使用for迴圈,才能夠讀取reader物件裡面的資料。

也就是說,當reader物件建立後,可透過迭代的方式遍巡檔案中的每一行資料。

因此,我們在上面的程式碼加上粗體字部份。

file=open('data.csv')reader=csv.reader(file)forrinreader:print(r)file.close()執行這個檔案就可以得到下面的結果:可以看到一組一組的list。

另一種方式是將reader物件轉換為Python串列。

如下粗體字部份,我們使用list()函式將reader物件轉換為串列。

importcsvfile=open('data.csv')reader=csv.reader(file)data_list=list(reader)file.close()print(data_list)執行上面的程式碼,會得到下圖所顯示的一個串列,串列中又包含著數個串列。

寫到這裡,我們就可以使用串列的操作方式來讀取裡面的資料。

比如說,可以使用data_list[1][0]取得第2個row中第1個column的值(由於行與列的中文翻譯容易產生混淆,在此一率使用row與column表示),也就是booker33。

寫入CSV要透過Python寫入資料並生成CSV檔案,一樣需要引入csv套件,並且建立writer物件來進行後續寫入資料等操作。

由於前面已經引入csv套件,我們可以跳過這個步驟,直接從建立writer物件開始。

建立writer物件我們已經知道,使用reader物件可以讓我們從CSV檔案裡面讀取資料。

若要反過來將資料寫入CSV檔案,則需要先建立一個writer物件。

建立一個writer物件的方式如下:file=open('store_data.csv',mode='w',newline='')writer=csv.writer(file)file.close()一開始一樣要先呼叫open()函式並傳入檔案名稱,以及寫入模式等等。

在這例子,我們傳入的CSV檔名為store_data.csv,這是我們將要建立的CSV檔案。

模式使用w(mode='w'),此為寫入模式。

並且後面加上newline=''的參數,以上設定將會打開一個可以被寫入的CSV檔案,名稱為store_data。

註:由於Windows系統下會幫每一行結尾多加一個看不見的”進位符號”,因此若你使用的是Windows系統,沒有設定newline=''的話,CSV檔案中的行距會變成兩倍大;使用Mac則沒有差異。

寫入資料建立完writer物件後,就可以對CSV檔案寫入資料。

writerow方法可以接受一行list串列,並將串列寫入檔案中。

例如,我們把下面這一行加在writer=csv.writer(file)的後面:writer.writerow(['apple','banana','cherry','dragonfruit'])執行後,在您的電腦上會產生一個store_data.csv的檔案,打開檔案可以看到裡面已經被寫入一行,內容如下圖所示:至此,已經完成寫入CSV的基礎步驟。

接下來您可能想要做一些變化,例如改變定位點符號。

delimiter原本預設的內容分隔符號為逗號。

如果想要使用其他符號來取代逗號作為分隔內容的定位點時,可以使用delimiter。

如下修正,建立writer物件時,我們多加入delimiter='\\t'(粗體字)。

就會將原本預設的逗號(,)分隔符號改為tab定位點。

file=open('store_data.csv',mode='w',newline='')writer=csv.writer(file,delimiter='\\t')file.close()字典方式讀寫CSV—DictReader與DictWriter目前為止提到的reader和writer物件都是以list串列的方式來處理CSV檔案。

如果想要讀取的CSV的資料是以字典的方式保存,或者是想要存成字典架構的CSV檔案,就要改用DictReader與DictWriter物件來處理。

尤其是CSV檔案中若含有標題列,使用DictReader與DictWriter物件來處理會比較方便。

DictReader物件還記得前面的data.csv嗎?由於這個CSV檔案本來就含有標題列,我們試著透過DictReader來讀取。

file=open('data.csv')reader=csv.DictReader(file)forrowinreader:print(row['username'],row['Id'],row['first_name'],row['last_name'])執行程式的結果如下:從上面的例子可知,我們不需要特別寫程式來跳過第一行標題列。

這是使用DictReader時的一個好處。

此外,DictReader會將標題列當作字典的Key來使用。

但要注意的是,若CSV檔案本身不存在標題列,DictReader就會將資料的第一行當作字典的Key來使用。

我們也可以透過在DictReader函式中傳入第二個引數,來將一組標題列寫入CSV檔案中。

假設先前的data.csv不存在標題,我們就可以將程式碼改成如下面粗體字部分。

file=open('data.csv')reader=csv.DictReader(file,['username','Id','first_name','last_name'])forrowinreader:print(row['username'],row['Id'],row['first_name'],row['last_name'])DictWriter物件至於寫入CSV的狀況。

在原本writer的地方,要改用DictWriter建立物件(csv.DictWriter)。

file=open('users.csv',mode='w')writer=csv.DictWriter(file,['Username','Id','FirstName','LastName'])file.close()我們原本在writerow的地方傳入list串列,在這裡要改為傳入字典。

如粗體字的地方顯示的,傳入的是一個key-value對應的字典。

writer.writerow({'Username':'booker33','Id':1,'FirstName':'Ana','LastName':'Booker'})如果想要將標題欄寫入CSV檔案的話,需要加上writeheader:writer.writeheader()至此,我們已經可以讀寫串列型態的CSV檔以及字典型態的CSV檔。

但是,這裡所謂的寫入,都是對整個檔案做覆蓋式的寫入,有時候我們需要的是在既有CSV檔案中追加新資料,這該如何處理?追加CSV檔案紀錄記得在寫入CSV的時候,我們會傳入一個mode參數,使用的是mode='w'。

這裡的w代表的是寫入資料的意思。

它會將我們每次讀取到的資料,完完整整的寫入檔案中。

如果原本的檔案中已經存在資料,這時候它會先把檔案中的原資料刪除,再覆寫上去。

file=open('store_data.csv',mode='w',newline='')writer=csv.writer(file)file.close()在某些狀況下,採用這方式非常方便又乾脆,但我們並非每次都想要採用這種方式,有時我們希望資料是不斷地累積上去。

這時就需要把前面的mode改為a(mode='a')。

舉例說明,檔案users.csv裡面已經有會員資料,我們可以採用mode='a'的方式開啟檔案,然後再將新資料添加進去:{'Username':'booker123','Id':2,'FirstName':'Jane','LastName':'Booker'}file=open('users.csv',mode='a')writer=csv.DictWriter(file,['Username','Id','FirstName','LastName'])writer.writerow({'Username':'booker123','Id':2,'FirstName':'Jane','LastName':'Booker'})file.close()夠過這樣的方式,就可以陸陸續續將很多筆資料寫入users.csv裡面。

前面提到的,都是在一個CSV檔下面所出現的情境,如果碰到了多個CSV檔需要被合併為一個CSV檔案時,該如何處理?合併多個CSV檔有時候,我們需要將多個CSV檔合併為一個CSV檔案。

例如,您擁有數個CSV檔,每個檔案裡面存放著每月的銷售資料。

這時候,如果想要依照「季」來儲存季度為資料,該如何對CSV檔案進行合併?在這裡,我們就來示範一下合併月銷售資料為季銷售資料的方式。

前提我們有三個CSV檔案,分別是sales07.csv、sales08.csv、sales09.csv三個檔案放在data資料夾中。

以七月份的銷售(sales07.csv)為例,檔案格式如下:欄位的標題為「日期」、「客戶名稱」、「產品名稱」、「單價」、「數量」、「小計」。

其他兩個檔案格式也跟七月份的銷售檔一樣。

我們要透過Python程式,將這三個檔案合併為一個名為salesQ3.csv的CSV檔案,並且儲存在同樣的data路徑下。

//sales07.csv日期,客戶名稱,產品名稱,單價,數量,小計2021/7/1,王先生,青森蘋果,500,2,10002021/7/4,李小姐,麝香葡萄,2000,5,100002021/7/5,張先生,愛文芒果,450,5,22502021/7/9,黃先生,巨峰葡萄,300,6,18002021/7/14,許先生,華盛頓蘋果,350,8,28002021/7/15,吳小姐,智利無籽葡萄,500,5,25002021/7/18,劉小姐,華盛頓蘋果,350,10,35002021/7/20,張小姐,火龍果,200,5,10002021/7/22,李先生,芭樂,200,5,1000引入套件先引入套件,需要csv與pathlib裡面的Path套件。

importcsvfrompathlibimportPath讀入檔案在讀入CSV檔案前,有幾個部分還需要我們事先準備好。

首先,要建立一個空白串例rows(rows=[]),這個串列未來可以用來儲存我們從各個CSV檔案中搜集讀到的資料。

接著,要建立一個變數skip_num,這個變數讓我們在等一下巡迴資料時可以跳過標題row。

我們先給定0作為skip_num的初始值(skip_num=0)。

因為在第一次讀入CSV檔案時,標題row需要被讀入,到了讀取第二個CSV檔案的時候,才需要跳過標題row。

最後,要取得data資料夾中的所有csv檔案。

我們使用Path來取得data的路徑,並且使用glob來取得data資料夾中所有的csv檔案。

其中*.csv可以取得所有副檔名為csv的檔案。

files=Path("data").glob("*.csv")我們可以使用for迴圈來觀察取得的CSV檔名(print(file)),同樣的也可以使用open逐一開啟CSV檔案(f=open(file))。

forfileinfiles:print(file)f=open(file)開啟檔案之後,就可以依照前面提過的方式建立reader物件(csv.reader(f))。

並且使用另一個for迴圈,巡迴取得檔案中的row(forrowinreader:),最後再把取得的row加入空白串例rows裡面(rows.append(row))。

還記得我們在開始前準備的空白串例rows(rows=[])吧。

reader=csv.reader(f)forrowinreader:**ifreader.line_num<=skip_num:continue**rows.append(row)在此,還要注意的一個地方是,我們需要一個可以跳過標題的機制。

因此,我們在迴圈中加上一個if判斷式,讓它比較reader.line_num與skip_num變數:ifreader.line_num<=skip_num:continuereader.line_num是從for迴圈迭代讀取的行數,如果這個行數尚未超過(小於或者是等於)我們想要跳掉的行數(skip_num)時,就讓整個判斷continue繼續,直到行數超過我們的設定值。

在這裡我們設定skip_num的值為0,因此,馬上就繼續執行下一段for迴圈程式。

但是當地一次執行完畢後,我們就重新指定skip_num的值,因為第一行是標題,把它改為skip_num=1,這樣就會把第二個CSV以後的標題給跳過。

rows=[]skip_num=0files=Path("data").glob("*.csv")forfileinfiles:f=open(file)reader=csv.reader(f)forrowinreader:ifreader.line_num<=skip_num:continuerows.append(row)f.close()skip_num=1到目前為止,我們已經把所有CSV檔案的資料都讀出來,並且存入rows串列中。

接下來就是要將這個串列寫入另外一個CSV檔案中。

寫入檔案首先我們使用open來開啟檔案,檔名為salesQ3.csv,路徑為data(data/salesQ3.csv),讀寫的模式為w,並加上newline。

接著建立writer物件,使用for迴圈將rows串列中的資料一行行的寫入。

f=open("data/salesQ3.csv",mode='w',newline="")writer=csv.writer(f)forrowinrows:writer.writerow(row)f.close()最後別忘記關閉檔案(f.close())。

以上就完成了合併CSV檔案的程式了。

完整程式碼下面是這個程式的完整程式碼,大家可以試試。

importcsvfrompathlibimportPath#讀入檔案rows=[]#最初讀入時,header也要讀入skip_num=0forfileinPath("data").glob("*.csv"):f=open(file)reader=csv.reader(f)forrowinreader:ifreader.line_num<=skip_num:continuerows.append(row)f.close()skip_num=3#寫入檔案f=open("data/salesQ3.csv",mode='w',newline="")writer=csv.writer(f)forrowinrows:writer.writerow(row)f.close()結語本篇介紹了CSV的讀寫以及合併多個檔案。

實際上,對CSV進行的操作還有很多種,例如您可以寫一隻程式來比對不同CSV檔案之間的資料,看看有沒有不同的地方?在比對出錯誤時提出警告?或者是將CSV的資料全部或部分轉換為EXCEL格式,或反向操作將EXCEL中的資料全部或部分轉換到CSV中。

你也可以試著取得它人存成CSV的資料,用心的方式呈現在自己的網站上。

以上使用場景,都很適合CSV檔案,大家不妨試試。

MorefromPythonEverywhere-fromBeginnertoAdvancedThisplaceisAllaboutPython.FromBeginnertoAdvancedprograming,byusingPython,youcandoanythingyouimagine.ReadmorefromPythonEverywhere-fromBeginnertoAdvancedAboutHelpTermsPrivacyGettheMediumappGetstartedSeanYeh441Followers#Taipei,InternetDigitalAdvertising「樂於發現與分享,才是最大贏家」FollowHelpStatusWritersBlogCareersPrivacyTermsAboutKnowable



請為這篇文章評分?