# File I/O
陳以哲 onion
----
### I/O 是什麼
Input / Output 的簡稱。
平常看到的終端機輸入輸出也是 I/O
分別是 stdin、stdout
---
## 終端機
----
### 檔案路徑
在電腦的檔案系統裡面,每個檔案都有一個**路徑**
例如桌面,他的路徑可以寫成:
```
# Windows:
C:/Users/使用者名稱/Desktop # 也可能在 OneDrive 裡面
# Linux:
/home/使用者名稱/Desktop
```
(這邊的檔案泛指資料夾)
----
### CLI
Command Line Interface
CLI 是用命令列跟電腦溝通的介面
與之相對的是 GUI (Graphical User Interface)
----
### CLI 概念
在終端機中,會在一個目錄下執行命令
這可以等價於「在 GUI 中看哪個資料夾」


<!-- 這邊將目錄 (directory) 跟資料夾 (Folder) 視為一樣 -->
----
### 用 CLI 操作電腦
在 Windows 中,終端機又叫**命令提示字元**
首先可以直接下 `cd`,就會顯示我們在哪個目錄底下

----
### 列出目錄下的檔案
Windows 中使用 `dir` 可以列出在目錄下的檔案

----
### 切換到指定目錄
再使用 `cd <目錄>` 可以指定要切到哪個目錄

可以用 `.` 代表這個目錄,`..` 代表上層目錄
----
### 創建新目錄
`mkdir` 可以創新目錄

----
### For Windows:
| 指令 | 指令來源 | 用途 |
| ----- | ---------------- | ---------------- |
| cd | change directory | 移動到指定的目錄 |
| dir | directory | 列出目錄下的檔案 |
| mkdir | make directory | 創建新的目錄 |
| cls | clear screen | 重整畫面 |
----
### For Mac/Linux:
| 指令 | 指令來源 | 用途 |
| ----- | ----------------------- | ---------------- |
| cd | 同 Windows | 同 Windows |
| mkdir | 同 Windows | 同 Windows |
| ls | list | 列出目錄下檔案 |
| pwd | print working directory | 顯示目前的目錄 |
| clear | clear | 重整畫面 |
----
### 絕對/相對路徑
絕對路徑 (Absolute Path) 是整個檔案系統中的路徑
相對路徑 (Relative Path) 是**相對於工作目錄**的路徑
----
### 絕對/相對路徑
例:對於 `D:/NTU/Sprout/Lecture`
- `D:/NTU/Sprout/Lecture` 是絕對路徑
----
### 絕對/相對路徑
例:對於 `D:/NTU/Sprout/Lecture`
工作目錄為 `D:/NTU/Sprout/`
- `./Lecture` 是相對路徑
<!-- .element: class="fragment" data-fragment-index="1" -->
- `Lecture` 是相對路徑
<!-- .element: class="fragment" data-fragment-index="2" -->
- `/Lecture` 非法
<!-- .element: class="fragment" data-fragment-index="3" -->
----
### 絕對/相對路徑
例:對於 `D:/NTU/Sprout/Lecture`
工作目錄為 `D:/NTU/Sprout/Lecture/Week8`
- `..` 是相對路徑
<!-- .element: class="fragment" data-fragment-index="1" -->
- `../../Lecture` 是相對路徑
<!-- .element: class="fragment" data-fragment-index="2" -->
- `../Lecture` 沒有這東西
<!-- .element: class="fragment" data-fragment-index="3" -->
----
### Python 的工作目錄
就是你執行 `python` 時的工作目錄

上圖 Python 的工作目錄就是 `D:/NTU/Sprout`
相對路徑就會從這個目錄開始算
----
### 補充
眼尖的你可能注意到了
Windows 的路徑好像是反斜線?
但 Python 不管是 `/` 或是 `\` 都可以吃
所以沒事
----
### 補充
在 Windows 中,如果你想切換 C 槽 / D 槽
直接 `C:` 或是 `D:`

----
### 練習
- 寫一個 `helloworld.py`
- 用 `cd`、`dir/ls` 找到 `helloworld.py`
- 用 `python` 執行 `helloworld.py`
- 不能用 vscode 的終端機 :)
---
## Python 中的檔案
----
在 Python 中,檔案可以被表示為**檔案物件**。
使用檔案物件,我們可以對檔案進行各種操作
[官方教學](https://docs.python.org/zh-tw/3/tutorial/inputoutput.html#reading-and-writing-files)
----
### `open()`
```python
f = open("filename", "mode")
```
開啟檔案,並回傳檔案物件
- `filename`: 要開啟的檔案路徑
- `mode`: 開檔的模式
----
### 來個 :chestnut:
```python
fp = open("myfile", "r")
content = fp.read()
print(content)
fp.close()
```
----
### 開檔模式
| mode | 作用 |
| ---- | ---- |
| r | 讀 |
| w | 寫 (會把原本的檔案覆蓋) |
| a | 接著寫 (在檔案最後面開始寫入) |
----
### 檔案模式
使用 `r` 讀檔要指定存在的檔案,否則會 error
但是使用 `w` 或是 `a` 可以使用不存在的 `filename`
Python 會自動建立一個檔案

----
### 關閉檔案
使用 `open()` 之後,要使用 `close()` 關閉檔案。
```python
fp = open("filename", "r")
# 一些操作...
fp.close()
```
----
### 關檔會怎麼樣
如果嘗試去存取已經關閉的檔案

----
### `with`
關閉檔案是必要的操作,卻容易忘記
可以用 `with` 語句,離開 `with` 後自動關檔
```python
with open("filename", "r") as fp:
# 一些操作...
# 這邊就關檔了
```
注意這邊的 `fp` 是變數名稱,想取什麼都可以!
---
## 常用操作
----
### 讀取檔案
常用的 methods:
```python
with open("myfile.txt", "r") as fp:
fp.read() # 讀取文字內容
fp.readline() # 讀一行
fp.readlines() # 讀很多行,回傳 list
```
注意 `readline()` 跟 `readlines()` 包含換行字元 `\n`
----
### 寫入檔案
```python
with open("myfile.txt", "w") as fp:
fp.write("This is line 1.")
```
寫入的時候不會包含換行字元 `\n`
----
### 接著寫檔案
```python
with open("myfile.txt", "a") as fp:
fp.write("\n")
fp.write("This is line 2.\n")
```
這時候 `myfile.txt` 長得像:
```
This is line 1.
This is line 2.
```
----
### 再寫入一次
觀察看看,如果接著用 `w` 開檔,會發生什麼事?
```python
with open("myfile.txt", "w") as fp:
fp.write("This is line 3.\n")
```
----
### 寫入的時機
多數時候 Python 不會馬上寫入
會等到「特殊的時機」
如關檔、buffer 滿了
```python
fp.write("This is line 1.")
fp.flush() # 把還沒寫入的內容寫入檔案
```
----
### 補充
開檔模式還有很多種
| mode | 作用 |
| ---- | ------------------ |
| r+ | 可以讀又可以寫 (a) |
| rb | 用二進位方式讀檔 |
| wb | 用二進位方式寫檔 |
| ... | ... |
----
### 練習
產生一個 Python 檔案,會從 1 印到 100
```python
print(1)
print(2)
print(3)
...
print(100)
```
---
## JSON
----
JSON 是一種檔案格式,常見於網路上做資料的交換
許多機器學習的資料都用 JSON 作為檔案格式
```json
{
"firstName": "John",
"lastName": "Smith",
"sex": "male",
"age": 25,
"address":
{
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021"
},
"phoneNumber":
[
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "fax",
"number": "646 555-4567"
}
]
}
# From Wikipedia
```
----
### Python 中的 JSON
需要 `json` 套件。
```python
import json
fp = open("data.json", "r")
content = json.load(fp)
print(content)
fp.close()
```
其實你會發現很像 dictionary。可參考[官方教學](https://docs.python.org/zh-tw/dev/tutorial/inputoutput.html#saving-structured-data-with-json)
----
### 讀寫 JSON
```python
content = json.load(fp) # 讀 fp 的 JSON 到 content
json.dump(content, fp) # 寫 content 到 fp,content 可以是 dictionary
```
注意有另外兩個函式 `loads()`、`dumps()`
他們處理的對象是字串而非檔案
----
### 練習
將以下內容存成 JSON,然後再讀這個 JSON file
最後 print 出 home 的電話號碼
可以練習看看用 python 輸出 json
```json
{
"firstName": "John",
"lastName": "Smith",
"sex": "male",
"age": 25,
"address":
{
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021"
},
"phoneNumber":
[
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "fax",
"number": "646 555-4567"
}
]
}
```
---
### Appendix
https://overthewire.org/wargames/bandit/
可以學習使用 linux command line!
----
### Reference
[Sprout Py 2024 Slides](https://docs.google.com/presentation/d/1X1uqxsrko65y5UyReWjJJMgAWNw7-sigMPYr5t7eU68/edit?usp=sharing)
---
## Thank You
{"title":"Python File IO","contributors":"[{\"id\":\"069820a6-3e96-4d49-99f2-2503b2c47d84\",\"add\":7464,\"del\":587}]","description":"陳以哲 onion"}