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

檔案操作流程

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

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

Text 檔案

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

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

模式參數的說明:

  • b:檔案是二進位制。
  • +:檔案可以讀寫。
  • r:read。
  • w:write。
  • a:append。
  • 讀取或寫入

    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 是可以疊代的資料類型,有 字串 List Tuple 等。

    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 (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 檔案教學與範例