# File I/O ## Sprout Py2021 @robert1003 ---- I/O = Input / Output = 輸入 / 輸出 <span>File I/O = 檔案輸入 / 輸出<!-- .element: class="fragment" data-fragment-index="2" --></span> ---- 檔案輸入輸出發生在什麼時候? ---- 輸入(Input):開啟檔案的時候 ![](https://i.imgur.com/8s2Fwcg.jpg) ---- 輸出(Output):儲存檔案的時候 ![](https://i.imgur.com/VlB9pil.jpg) --- ## Outline <!--- + 一些準備 ---> + 目錄 + 檔案 + 路徑 + 開檔 + 讀檔 + 寫檔 + 關檔 + 常用寫法 以下是一些補充 + pickle + JSON --- # 目錄(Directory) ---- 其實就是資料夾 <span>桌面也是一個目錄(資料夾)<!-- .element: class="fragment" data-fragment-index="1" --></span> --- # 檔案(File) ---- 這些都是檔案: + txt + zip + docx + py + cpp + ... ---- 檔案可以分成兩種: | 文字檔(text file)| 二進位檔(binary file)| |-|-| |你看得懂|你看不懂| | html, txt | png, zip, docx | | ![](https://i.imgur.com/HBqN8Wh.png) | ![](https://i.imgur.com/Rm39H8Z.png) | --- # 路徑(Path) ---- 其實就是檔案的位置 ---- 路徑也可以分成兩種 <span>絕對路徑&相對路徑<!-- .element: class="fragment" data-fragment-index="2" --></span> ---- ## 絕對路徑 可以看成地址(? ---- Windows: `C:\windows\a.dll` <span>C槽底下的windows資料夾裡的a.dll<!-- .element: class="fragment" data-fragment-index="3" --></span> ---- Linux: `/tmp/b07902047/out.png` <span>根目錄底下的tmp底下的b07902047的out.png<!-- .element: class="fragment" data-fragment-index="4" --></span> ---- ## 相對路徑 直接舉例可能比較好懂 ---- `hello2.py` <span>當前目錄下的hello2.py<!-- .element: class="fragment" data-fragment-index="3" --></span> ---- `fileIO/hello3.py` <span>當前目錄下的fileIO資料夾裡面的hello3.py<!-- .element: class="fragment" data-fragment-index="3" --></span> ---- `../hello.py` <span>上一層資料夾的hello.py<!-- .element: class="fragment" data-fragment-index="3" --></span> ---- `../robert/ans/hw1.pdf` <span>上一層資料夾的robert資料夾裡面的ans資料夾裡面的hw1.pdf<!-- .element: class="fragment" data-fragment-index="3" --></span> ---- 所以他們差在哪裡? <span> 絕對:一定從最上面的目錄開始描述 相對:從當前目錄開始描述<!-- .element: class="fragment" data-fragment-index="3" --></span> --- # 開檔 ---- 一個指令 ```python [file_object] = open([file_path], [mode]) ``` ```python f = open('hello.py', 'r') ``` <span>file_object: 檔案物件 file_path: 檔案路徑 mode: 開檔模式 <!-- .element: class="fragment" data-fragment-index="4" --></span> ---- 檔案物件(file_object)? <span>可以自己取名字<!-- .element: class="fragment" data-fragment-index="0" --></span> <span>讓python可以存取電腦上的檔案<!-- .element: class="fragment" data-fragment-index="1" --></span> ---- 檔案路徑(file_path)? <span>就是剛剛講的路徑 絕對路徑跟相對路徑都可以<!-- .element: class="fragment" data-fragment-index="0" --></span> ---- 開檔模式(mode)? <span>簡單來說就是跟python講你現在要拿這個檔案幹嘛<!-- .element: class="fragment" data-fragment-index="0" --></span> <span> | 模式 | 功能 | |-|-|-| | r | 讀 | | w | 寫 | | a | 寫在最後面 | <!-- .element: class="fragment" data-fragment-index="0" --></span> <span>w: 如果檔案不存在會建一個新的,存在的話會覆蓋原本的檔案<!-- .element: class="fragment" data-fragment-index="0" --></span> --- # 讀檔 ---- 兩個指令 ---- 讀一整列 ```python [string] = [file_object].readline() ``` ```python f = open('hello.txt', 'r') s1 = f.readline() s2 = f.readline() print(s1, end='') print(s2, end='') ``` <span>string: 把回傳的字串存到string裡 file_object: 檔案物件 <!-- .element: class="fragment" data-fragment-index="4" --></span> ---- 讀特定數量的字元 ```python [string] = [file_object].read([length]) ``` ```python f = open('hello.txt', 'r') s = f.read(11) print(s, end='') ``` <span>string: 把回傳的字串存到string裡 file_object: 檔案物件 length: 要讀幾個字元,型別是int <!-- .element: class="fragment" data-fragment-index="4" --></span> ---- 如果不打length會發生什麼事? ```python s = f.read() ``` <span>他會一次把整個檔案讀進來<!-- .element: class="fragment" data-fragment-index="3" --></span> --- # 寫檔 ---- 一個指令 ```python [file_object].write([string]) ``` ```python f = open('hola.txt', 'w') f.write('Hola, mondo!\n') f.write('Me llamo Robert.\n') ``` <span>string: 要寫入的字串 file_object: 檔案物件 <!-- .element: class="fragment" data-fragment-index="4" --></span> --- # 關檔 ---- 一個指令 ```python [file_object].close() ``` ```python f.close() ``` <span>file_object: 檔案物件 <!-- .element: class="fragment" data-fragment-index="4" --></span> ---- 什麼時候要關檔? 使用完的時候(廢話),暫時不需要他了 ---- 一定要關檔案嗎? ---- 不關檔案的壞處 1. 佔你記憶體的空間,讓你程式變慢 2. 在你關檔之前,檔案都不會被真的寫入 3. 你有可能開超過數量上限的檔案 4. 看起來很不專業 ---- 關於2.如果你想馬上寫入檔案怎麼辦? <span> ```python f = open('hola.txt', 'r') print(f.read(), end='') f.flush() ``` <!-- .element: class="fragment" data-fragment-index="4" --></span> --- # 常用寫法 ---- 常用寫法 1 ```python with open([file_name], [mode]) as [file_object]: # do something ``` ```python with open('hola.txt', 'r') as f: print(f.read(), end='') ``` 只有在那個迴圈裡檔案才是開的(所以不用關檔) <span>注意上面的寫法等於下面的寫法:<!-- .element: class="fragment" data-fragment-index="4" --></span> <span> ```python f = open('hola.txt', 'r') print(f.read(), end='') f.close() ``` <!-- .element: class="fragment" data-fragment-index="4" --></span> ---- 常用寫法 2 ```python with open([file_name], 'r') as [file_object]: for [line] in [file_object]: # do something ``` ```python with open('hello.txt', 'r') as f: for line in f: print(line, end='') ``` 遍歷所有列 ---- 常用寫法 3 ```python with open([file_name], 'w') as [file_object]: print([string], file = [file_object]) ``` ```python with open('bonjour.txt', 'w') as f: print('Bonjour, monde', file=f, flush=True) print("Je m'appelle Robert", file=f) ``` 這樣就不用寫`f.write`了(? 可以直接用`print` --- # 小練習 ---- 找出這個[檔案](https://gist.github.com/robert1003/0794860663de4177dd88e951132b2d21)裡最大的數字 找到了之後可以到[這裡](https://neoj.sprout.tw/problem/8763/)確認答案 --- # pickle ---- ![](https://i.imgur.com/n6HianH.jpg) 小黃瓜?? ---- 沒拉,pickle是一個直接存物件的東西 官網:[pickle](https://docs.python.org/3/library/pickle.html) ---- 怎麼使用? <span> ```python # pickle.dump([object_name], [file_object]) # [var_name] = pickle.load([file_object]) import pickle # dump, load dic = {1: 'a', 2: 'b', 3: 'c'} print(dic) with open('demo', 'wb') as f: pickle.dump(dic, f) with open('demo', 'rb') as f: dic2 = pickle.load(f) print(dic2) ``` <!-- .element: class="fragment" data-fragment-index="4" --></span> ---- 基本上任何python裡面的東西都可以用pickle存成一個二進位檔(binary file) --- # JSON ---- JSON (JavaScript Object Notation) 是一種人看得懂的存資料方法 官網:[JSON](https://www.json.org/json-en.html) ---- 如果把它當成python物件來看,他其實就只是由 list 跟 dict 還有 value 所組成 * `{}` 組成一個 dict * `[]` 組成一個 list * value 就是 字串、整數、true、false、null * dict 跟 list 可以互包 ---- 來看個例子: ![](https://i.imgur.com/3XeWgHY.png) ---- 如果你想挑戰自己,可以自己寫寫看 json parser XD 你可能會需要用到遞迴的觀念(我們沒教) ---- 如果你很懶也沒關係,我們來看看怎麼使用 `json` 這個套件~ ---- 我這邊示範的`sample.json`檔可以從[這裡](https://gist.githubusercontent.com/robert1003/4dbb3abb8b7d63aae1950f459ca7d4fa/raw/3ac196eb95d7034241bb676220aeb2df76d9ddf5/sample.json)下載~ ``` { "arguments": { "number": 10 }, "url": "http://localhost:8080/restty-tester/collection", "method": "POST", "header": { "Content-Type": "application/json" }, "body": [ { "id": 0, "name": "name 0", "description": "description 0" }, { "id": 1, "name": "name 1", "description": "description 1" } ], "output": "json", "delayed": false, "success": true, "ttl": 256.0, "secret": null } ``` ---- * `json.load`:從檔案讀 json * `json.loads`:從字串讀 json ```python # [var_name] = json.load([file_object]) # [var_name] = json.loads([string_name]) with open('sample.json', 'r') as f: obj = json.load(f) print(obj) with open('sample.json', 'r') as f: obj = json.loads(f.read()) print(obj) ``` ---- * `json.dump`:把 dict 或 list 換成 string 然後寫進檔案 * `json.dumps`:把 dict 或 list 換成 string ```python # json.dump([dict_or_list], [file_object]) # json.dumps([dict_or_list]) # a 就是 sample.json 讀出來的結果 a = {'arguments': {'number': 10}, 'url': 'http://localhost:8080/restty-tester/collection', 'method': 'POST', 'header': {'Content-Type': 'application/json'}, 'body': [{'id': 0, 'name': 'name 0', 'description': 'description 0'}, {'id': 1, 'name': 'name 1', 'description': 'description 1'}], 'output': 'json', 'delayed': False, 'success': True, 'ttl': 256.0, 'secret': None} with open('sample2.json', 'r') as f: json.dump(a, f, indent=4) # indent 參數可以不加,加了是為了排版 ㄖ s = json.dumps(a, indent=4) print(s) ```
{"metaMigratedAt":"2023-06-15T07:50:37.635Z","metaMigratedFrom":"YAML","title":"File I/O","breaks":true,"slideOptions":"{\"transition\":\"slide\"}","contributors":"[{\"id\":\"3d3e812e-7132-40aa-b06f-8f5380bf64d1\",\"add\":8447,\"del\":284}]"}
    1117 views