Python 自學第九天:讀取、寫入 Text、JSON 或 CSV 檔案

程式時常需要處理各種不同的檔案。理解如何讀取、寫入 Text 檔案非常重要。除此之外,網路上的公開資料 (Open Data) 也常會使用 JSONCSV 格式的檔案,因此,我們也需要了解相關的操作方式。

檔案操作流程

開啟 > 讀取或寫入 > 關閉。

如果不想每次手動關閉檔案,或怕自己忘記關閉檔案,可以使用 with 關鍵字實作。

Text 檔案

開啟

1
myFile = open(檔案路徑, mode) # 將回傳的 file 物件存在 myFile 變數中。

open():會 return 一個 file 物件。file 物件會有一些和檔案相關的變數和函式。
檔案路徑:相對路徑或絕對路徑。
mode:檔案開啟模式。不寫,預設是:“r”,表示讀取檔案。

模式參數的說明:

  • b:檔案是二進位制。
  • +:檔案可以讀寫。
  • r:read。
  • w:write。
  • a:append。
檔案開啟模式 說明 檔案開啟的游標位置
r, rb 只讀取檔案 最前端
r+, rb+ 檔案可讀寫 最前端
w, wb 如果檔案不存在,建立新的檔案,並且寫入資料。
如果檔案存在,覆蓋舊的資料,寫入新的資料
最前端
w+, wb+ 同上,但是檔案可以讀寫。 最前端
a, ab 如果檔案不存在,建立新的檔案,並且寫入資料。
如果檔案存在,打開檔案,從資料尾部,寫入新的資料,不會覆蓋舊的內容
資料結尾
a+, ab+ 同上,但是檔案可以讀寫。 資料結尾

讀取或寫入

1
2
3
4
5
# myFile 變數是一個 file 物件,有一些和檔案相關的變數和函式
# 以「.」呼叫
myFile.read()
myFile.readline()
myFile.readlines()

read():讀取檔案全部內容,並且回傳。
read(n):讀取寬度 n 的字節,並且回傳。
readline():一次讀取一整行,包括結尾的換行符號 \n,並且回傳。如果讀取完第一行後再呼叫一次,則從上次游標結束的地方開始讀取,也就是會讀取第二行,以此類推。
readline(n):讀取寬度 n 的字節,並且回傳。再呼叫一次,則從上次游標結束的地方開始讀取一整行 (如果沒有傳入參數) 或讀取寬度 n 的字節。
readlines():讀取所有行,並且以 List 格式回傳。
readlines(n):「從第一個元素」到「n 字節所在的元素」,以 List 格式回傳。

1
2
3
4
# myFile 變數是一個 file 物件,有一些和檔案相關的變數和函式
# 以「.」呼叫
myFile.write(str)
myFile.writelines(seq)

write(str):寫入資料。str 是欲寫入的字串。
writelines(seq):寫入資料。sequence 是可以疊代的資料類型,有字串ListTuple 等。

關閉

1
myFile.close()

close():關閉檔案。檔案關閉後無法再讀取或寫入。

一般讀取或寫入流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 開啟
f1 = open("file1.txt", "w") # 檔案路徑以相對路徑表示,寫入模式
# 操作:寫入
f1.write("測試 Python 第一行\n")
data = ["這是第二行", ",接在第二行後面\n", "我是 Jenifer\n", "想要第三行"]
f1.writelines(data)
# 關閉
f1.close()


# ------- 檔案打開長這樣 -------
# 測試 Python 第一行
# 這是第二行,接在第二行後面
# 我是 Jenifer
# 想要第三行
# ---------------------------


# 開啟
f1 = open("file1.txt", "r") # 檔案路徑以相對路徑表示,讀取模式
# 操作:讀取
line1 = f1.readline()
print(line1)
lines = f1.readlines()
print(lines)
# 關閉
f1.close()

# 輸出結果:
# 測試 Python 第一行
#
# ['這是第二行,接在第二行後面\n', '我是 Jenifer\n', '想要第三行']

因為 readline() 會連換行符號 \n 也一起讀取,所以 line 23 會是一個空白行。

有一個小坑,如果沒有寫 line 8 的關閉檔案,但是在 line 20 卻將同一個檔案指給另一個變數,例如:f2 = open("file1.txt", "r"),不會報錯,但是輸出的結果會出現異常。

1
2
3
# 輸出結果:
#
# []

在 line 6 執行結束時,游標已經在 file1.txt 檔案的資料尾端。因為檔案沒有關閉再打開,因此當它被指給新的變數 f2 時,游標就已經在「資料尾端」了,再向後也讀取不到任何資料。

with 關鍵字實作

怕忘記關閉檔案,造成錯誤,改用 with 關鍵字實作。

1
2
3
4
5
6
7
8
9
10
with open("file1.txt", "w") as f1:
f1.write("測試 Python 第一行\n")
data = ["這是第二行", ",接在第二行後面\n", "我是 Jenifer\n", "想要第三行"]
f1.writelines(data)

with open("file1.txt", "r") as f2:
oneline = f2.readline()
print(oneline)
lines = f2.readlines()
print(lines)

另外讀取多行的方式

while 迴圈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
with open("file1.txt", "r") as f:
line=f.readline()
while line!='':
print(line)
line=f.readline()

# 輸出結果:
# 測試 Python 第一行

# 這是第二行,接在第二行後面

# 我是 Jenifer

# 想要第三行

for … in

1
2
3
4
5
6
with open("file1.txt", "r") as f:
for line in f:
print(line)

# 輸出結果:
# 同上一組程式碼

在檔案的後方新增資料

1
2
with open("file1.txt", "a") as f:
f.write(",新增的字串!")

JSON

JSON (JavaScript Object Notation),又稱作 JavaScript 物件表示法,被設計用來讓人容易理解、閱讀和方便交換、傳遞資料。

引入內建 json 模組,使用模組內的函式來操作 JSON 字串資料檔案物件。關於檔案的操作步驟和 Text 檔案類似。

JSON 字串資料

1
2
json.dumps(Python數據結構)   # 回傳 JSON 字串資料,類似 print(data)
json.loads(JSON字串資料) # 回傳 Python 數據結構,類似 input()

注意:結尾有 s。

這邊不是操作檔案,只是操作 JSON 字串資料。說真的,Python 數據結構 (不含 Set) 中的 List、字典資料和 JSON 資料長得一模一樣 … 唯二差別是:

  • JSON 字串資料中,Tuple 會被轉換成 List
  • Python 數據結構中:空值用 None 表示。JSON 字串資料中:空值用 null 表示。

傳入 Python obj,回傳 JSON str

1
2
3
4
5
6
7
import json
python_data = [["name"], {"test": ("orange", None, 0.1, 20)}]
json_str = json.dumps(python_data)
print(json_str)

# 輸出 JSON str:
# [["name"], {"test": ["orange", null, 0.1, 20]}]

json.dumps(python_data):json 模組內的 dumps() 可以將 Python 數據結構 python_data 轉換成 JSON 字串,並且回傳。

傳入 JSON str,回傳 Python obj

1
2
3
4
5
6
7
import json
json_str = '[["name"], {"test": ["orange", null, 0.1, 20]}]'
python_data = json.loads(json_str)
print(python_data)

# 輸出 Python obj:
# [['name'], {'test': ['orange', None, 0.1, 20]}]

json.loads(json_str):json 模組內的 loads() 可以將 JSON 字串 json_str 轉換成 Python 數據結構,並且回傳。

JSON 檔案物件

1
2
json.dump(Python數據結構, 檔案物件)   # 類似 myFile.write(str)
json.load(檔案物件) # 類似 myFile.read()

注意:結尾沒有 s

寫入

1
2
3
4
5
6
7
import json
with open("config.json","w") as f:
data = [["name"], {"test": ("orange", None, 0.1, 20)}]
json.dump(data, f)

# ----------- config.json 檔案打開長這樣 -----------
# [["name"], {"test": ["orange", null, 0.1, 20]}]

json.dump(data, fp):json 模組內的 dump() 可以將 Python 數據結構 data 寫入 JSON 格式的 fp 檔案物件。

讀取

1
2
3
4
5
6
7
8
9
import json
with open("config.json","r") as f:
data = json.load(f)
print(data)
print(data[1]["test"])

# 輸出結果:
# [['name'], {'test': ['orange', None, 0.1, 20]}]
# ['orange', None, 0.1, 20]

json.load(fp):json 模組內的 load() 可以用來讀取 JSON 格式的 fp 檔案物件,並且回傳 Python 數據結構

CSV 檔案

CSV (Comma-Separated Values),又被稱為逗號分隔值字元分隔值,因為可以用其他的字元取代逗號。

引入內建 csv 模組,使用模組內的函式來操作 CSV 的 List、Tuple、Set 資料檔案物件。關於檔案的操作步驟和 Text 檔案類似。

1
2
csv.writer(csvfile, delimiter)     # 類似 myFile.write(str)
csv.reader(csvfile) # 類似 myFile.read()

csv.writer():會回傳一個寫入物件,有不同的函式,執行不同的寫入功能。
delimiter:可以指定分隔的字元。不寫,預設逗號
csv.reader():會回傳一個二維 List。

事實上在 Python 文件 csv 模組 中提到:

  • csv.writer() 的參數 csvfile 需要含有 write() 函式的功能。我目前學到也只查到,只有檔案物件有這個功能,List、Tuple、Set 資料都沒有 write() 函式。
  • csv.reader() 的參數 csvfile 需要是可以疊代的資料,包含檔案物件List、Tuple、Set 資料
  • 如果 csvfile檔案物件的話,一定要給予 newline="" 參數。

csv.writer():csvfile can be any object with a write() method. If csvfile is a file object, it should be opened with newline=''.

csv.reader():csvfile can be any object which supports the iterator protocol and returns a string each time its __next__() method is called - file objects and list objects are both suitable.

If csvfile is a file object, it should be opened with newline=''.

CSV 類型之 List、Tuple、Set 資料

只有 csv.reader(csvfile) 可以用。由下面的例子可以看到,Set 資料會刪去重複的資料,並且前後順序不一樣。

1
2
3
4
5
6
7
8
9
10
11
12
13
import csv
list_data = ["one,two,three","100,150,300"]
set_data = {"1,2,3,4", "5,6,7,8", "5,6,7,8"}
for row in csv.reader(list_data):
print(row)
for row in csv.reader(set_data):
print(row)

# 輸出結果:
# ['one', 'two', 'three']
# ['100', '150', '300']
# ['5', '6', '7', '8']
# ['1', '2', '3', '4']

csv.reader():會回傳一個二維 List,可以用 for … in 語法,取得每一列 (row)。

CSV 檔案物件

寫入

1
2
3
4
5
6
7
8
9
10
11
import csv
with open("example.csv", "w", newline="") as csvfile:
wr = csv.writer(csvfile)
wr.writerow(["name", "age", "ID"])
wr.writerow(["Jenifer", 10, "a12345"])
wr.writerow(["Marry", 12, "a12400"])

# ------ example.csv 檔案打開長這樣 ------
# name,age,ID
# Jenifer,10,a12345
# Marry,12,a12400

csv.writer(csvfile):csv 模組內的 writer(),確認好要寫入的檔案 csvfile 後,會回傳一個寫入物件 wr
writerow():寫入物件的函式,可以將一維的 List、Tuple、Set 資料寫入檔案。

1
2
3
4
5
6
7
8
9
import csv
list_2d = [
["name", "age", "ID"],
["Jenifer", 10, "a12345"],
["Marry", 12, "a12400"]
]
with open("example.csv", "w", newline="") as csvfile:
wr = csv.writer(csvfile)
wr.writerows(list_2d)

writerows():寫入物件的函式,可以將二維的 List、Tuple、Set 資料寫入檔案。

讀取

1
2
3
4
5
6
7
8
9
import csv
with open("example.csv", newline="") as csvfile:
for row in csv.reader(csvfile):
print(row)

# 輸出結果:
# ['name', 'age', 'ID']
# ['Jenifer', '10', 'a12345']
# ['Marry', '12', 'a12400']

csv.reader(csvfile):會讀取 csvfile 檔案,回傳一個二維 List,可以用 for … in 語法,取得每一列 (row)。

參考資料:
彭彭的課程:Python 文字檔案的讀取和儲存
Python 讀取與寫入 CSV 檔案教學與範例