# 檔案操作

## 列出檔案目錄

在操作檔案之前，可以先使用以下的命令來列出目前的目錄中所有的檔案列表：

```
>>> import os
>>> os.listdir()
['.ipynb_checkpoints', 'Chapter02.ipynb']
```

os.listdir()會傳回一個串列，其中就包含了所有目前中的檔案，想要顯示目前的檔案數量，只要如前面在介紹串列的操作中所使用的len函數一樣，透過 len來計算串列的長度，就等於是知道了目前目錄中的檔案數量。

```
>>> import os
>>> os.listdir()
['.ipynb_checkpoints', 'Chapter02.ipynb']
>>> n = len(os.listdir())
>>> print("There are {} files in this directory!".format(n))
There are 2 files in this directory!
```

## 建立資料夾&#x20;

os模組除了列出檔案名稱之外，也可以透遇mkdir來建立資料夾，操作如下：

```
>>> os.mkdir("data")
>>> os.listdir()
['.ipynb_checkpoints', 'Chapter02.ipynb', 'data']
```

## 寫入檔案

要寫入檔案需要先指定檔案名稱，然後執行開始檔案，再把開啟後的結果放在一個變數物件中，之後就可以透過該指標對這個檔案進行存取，結束不使用之後再把檔案關閉即可。以下是一個開啟檔案，寫入一個字串之後再把檔案關閉的程式範例：

```python
>>> fp = open("mydata.txt", "wt")
>>> fp.write("This is my data!\n")
17
>>> fp.close()
>>> os.listdir()
['.ipynb_checkpoints', 'Chapter02.ipynb', 'data', 'mydata.txt']
```

{% hint style="warning" %}
請注意，在第2行的字串中最後面那個「\n」的符號是換行記號，沒有這行的話，後面的資料會被串接在這一行的後面。
{% endhint %}

在開啟檔案的時候，檔案名稱後面那個參數就是用來指定要對檔案存取的方式，有以下幾種可用的指示元：

| mode | 說明       |
| ---- | -------- |
| r    | 讀取       |
| a    | 附加資料到檔案中 |
| w    | 寫入       |
| x    | 建立檔案     |

其中，如果w和a最大的差別在於是否需要保留原有檔案中的資料，如果使用w的話，會把原有的檔案資料清掉重寫，而a則會讓新的資料附加在原有的資料的後面。以下的例子是使用a來開啟之前的檔案，再寫入一些資料的例子：

```python
>>> fp = open("mydata.txt", "a")
>>> fp.write("This is 2nd line!\n")
18
>>> fp.close()
```

在上面的4個指字元之後還可以再選擇以下的兩種其中之一，特別說明要存取的資料是何種型式：

| 模式 | 說明                              |
| -- | ------------------------------- |
| t  | 文字模式，這也是預設的模式                   |
| b  | 二進位模式，主要是為了處理非可讀取的二進元檔案，如圖形檔等格式 |

一般來說我們都只要使用預設的模式，以文字檔的方式來存取資料就可以了。

## 從檔案中讀取資料

在前述的程式中寫入的文字資料，要如何才能夠把它讀取出來呢？同樣也是使用open函數開啟檔案，在取得檔案物件之後，就可以利用read, readline, readlines來讀取檔案中的資料，此三個函數主要的差異在如下表所列：

| 函數名稱      | 說明                                |
| --------- | --------------------------------- |
| read      | 一次讀取檔案中的所有資料                      |
| readline  | 一次讀取檔案中的一行資料                      |
| readlines | 一次讀取檔案中的資料，但是把資料分成一列列，逐列放到串列資料結構中 |

以下的程式是把之前的檔案都讀取出來之後的比較：

```python
fp = open("mydata.txt")
print(fp.read())
fp.seek(0)
print(fp.readline())
fp.seek(0)
print(fp.readlines())
fp.close()
```

{% hint style="info" %}
第3行、第5行的seek是用來調整目前要讀取的資料的指標位置用的，seek(0)就表示要回到檔案的最前面。
{% endhint %}

以下是程式輸出的結果：

```
This is my data!
This is 2nd line!

This is my data!

['This is my data!\n', 'This is 2nd line!\n']
```

同學們可以看得出來差別了嗎？

## with的用法

因為每一次使用檔案都要開檔和關檔，如果這個檔案打開之後只做了一些事就要關檔，並不會在其它的地方繼續使用的話，使用with可以簡化一些程序，也避免檔案打開之後就忘記關閉的情形，前面的程式如果使用with的話，可以改寫如下：

```python
with open("mydata.txt") as fp:
	print(fp.read())
	fp.seek(0)
	print(fp.readline())
	fp.seek(0)
	print(fp.readlines())
```

改完之後功能是一樣的喔。
