<style>
.red {
color: red;
}
.blue{
color: blue;
}
.green{
color: green;
}
</style>
# 檔案存取
## 8-1 認識檔案路徑
- 檔案或資料夾存放在儲存裝置的方式取決於**檔案系統(File System)**
- **檔案系統(File System)** 會找出檔案存放在儲存裝置的哪個位置,進而讀取上面的資料
- 不同電腦的作業系統(Operation System),可能採用不同的檔案系統
1. MS-DOS的檔案系統為FAT(File Allocation Table)
2. Windows 7/8/10的檔案系統為FAT32、NTFS(New Technology File-System)或exFAT(Extended File Allocation Table)
## 8-2 寫入檔案
### 8-2-1 建立檔案物件
- 在Python程式中,無論是要讀取還是寫入檔案資料,<span class='red'>都必須透過中介的檔案物件</span>
- 我可以使用下方的open( )函示來建立物件。當建立成功時會回傳檔案物件;相反的,當建立失敗時會發生錯誤
```python=
open(file, mode)
# file為欲儲存的檔案路徑和名稱
# mode是檔案物件的存取模式,常用的有6種
```
- 常用的有6種mode:
1. "**r**": 讀取檔案,若無此檔案會出現錯誤
2. "**w**": 寫入檔案,若無此檔案則會直接建立檔案。另外<span class='red'>寫入資料前會將檔案內的資料全部清除</span>
3. "**a**": 入檔案,若無此檔案則會直接建立檔案。另外<span class='red'>寫入的資料會附加在原檔案內容的後面</span>
4. "**r+**": 以讀寫模式開啟檔案,**會從檔案開頭寫入資料並覆蓋掉原始的內容**,若無此檔案會出現錯誤
5. "**w+**": 以讀寫模式開啟檔案,**會從檔案開頭寫入資料並先清除原檔案的內容**,若無此檔案則會直接建立檔案
6. "**a+**": 以讀寫模式開啟檔案,**會從檔案開頭寫入資料並附加在原檔案內容的後面,若無此檔案則會直接建立檔案
```python=
# 注意要使用跳脫序列 "\\" 來表示 "\"
# 使用絕對路徑(absolute path)
fileObject = open("D:\\vitas\\test.py", "r")
# 在絕對路徑前面加上r,表示此字串為原始字串(raw string)
# 這樣就不必使用跳脫序列 "\\" 來表示 "\"
fileObject = open(r"D:\vitas\test.py", "r")
```
### 8-2-2 將資料寫入檔案
```python=
# 將資料寫入檔案
fileObject = open("D:\\vitas\output.txt")
# 檔案物件提供的write()方法能將資料寫進檔案
fileObject.write("大家好!")
# 要記得關閉檔案
fileObject.close()
```
## 8-3 讀取檔案
- 從檔案讀取資料的步驟如下:
1. <span class='red'>開啟檔案</span>: 使用open( )函式來建立檔案物件
2. <span class='red'>讀取檔案</span>: 使用檔案物件提供的方法來讀取資料(包含**read( )** , **readline( )** 及**readlines( )** )
3. <span class='red'>關閉檔案</span>: 使用檔案物件提供的close( )方法關閉檔案
### 8-3-1 使用read()方法從檔案讀取資料
```python=
read([n])
# 指標一開始是指向檔案開頭
# 上述語法會從檔案指標處讀取參數n所指定之個數的文字,然後傳回該字串
# 若參數n省略不寫,就以字串的形式回傳檔案中所有的資料
```
```python=
# 若參數n省略不寫,就以字串的形式回傳檔案中所有的資料
fileObject = open("D:\\test.txt", "r")
content = fileObject.read()
print(content)
fileObject.close()
```
```python=
# 上述語法會從檔案指標處讀取參數n所指定之個數的文字,然後傳回該字串
fileObject = open("D:\\test.txt", "r")
str = fileObject.read([6])
print(content)
fileObject.close()
```
### 移動檔案指標
- **檔案指標**會指向目前讀取或寫入到哪個位置
- 若要自行移動,可以使用指令<span class='red'>seek( )方法,來將檔案指標移到第offset+1個位元組(byte)</span>
```python=
fileObject.seek(offset)
```
```python=
fileObject = open("D:\\vitas\\test.txt", "r")
# 移動指標
fileObject.seek(1)
# 移動指標到開頭
fileObject.seek(0)
fileObject.close()
```
### 8-3-2 使用readline()方法從檔案讀取資料
- readline( )方法可以從檔案讀取**一行**資料(**遇到換行\n**),然後回傳該字串
- <span class='red'>若傳回空字串,則表示抵達檔案結尾</span>
```python=
fileObject = open("D:\\vitas\\test.txt", "r")
content = fileObject.readline()
while content!='':
print(content)
content = fileObject.readline()
# print出後繼續讀取一行資料
fileObject.close()
```
```python=
# 下方程式結果與上方相同
fileObject = open("D:\\vitas\\test.txt", "r")
# 使用for迴圈印出每一行
for line in fileObject:
print(line)
fileObject.close()
```
### 8-3-3 使用readlines()方法從檔案讀取資料
- readlines( )方法可以從檔案讀取**所有行**的資料,然後以串列(list)的形式傳回所有行
```python=
fileObject = open("D:\\vitas\\test.txt", "r")
content = fileObject.readlines()
print(content)
for line in content:
print(line)
fileObject.close()
```
## 8-4 with敘述
- 在檔案存取結束後,我們會使用close( )函式來關閉檔案物件,否則檔案容易被竄改
- 但若怕忘記解close( ),則<span class='red'>可以使用with敘述,來將存取檔案的動作包裝在一個區塊</span>
- 也就是依但程式執行動作離開區塊,就會自動關閉檔案物件
```pytohn=
with open(file, mode) as fileObjectName:
STATEMENT
```
```python=
with open("D:\\vitas\\test.txt", "r") as fileObject:
content = fileObject.readlines()
print(content)
for line in content:
print(line)
```
## 8-5 管理檔案與目錄
### 8-5-1 檢查檔案或目錄是否存在
```python=
os.path.exists("D:\\")
# 若存在則會回傳True,反之則回傳False
```
### 8-5-2 檢查路徑是否為檔案或目錄
```python=
os.path.isdir("D:\\")
# 若路徑為目錄則會回傳True,反之則回傳False
os.path.isfile("D:\\vitas\\test.txt")
# 若路徑為檔案則會回傳True,反之則回傳False
```
- 前面我們有提到,如果在閱讀模式下去開啟不存在的檔案會發生錯誤。因此可以使用<span class='red'>isfile( )來確認要讀取的檔案是否存在</span>
```python=
import os.path
if os.path.isfile("D:\\vitas\\test.txt"):
with open("D:\\vitas\\test.txt", "r") as fileObject:
content = fileObject.readlines()
for line in content:
print(line)
else:
print("此檔案不存在!")
```
### 8-5-3 取得檔案的完整路徑
```python=
os.path.abspath("test.txt")
# abspath("FILE")函式可以取得參數file檔案之絕對路徑
```
>Output
>> 'D:\\vitas\\test.txt'
### 8-5-4 取得檔案的大小
```python=
os.path.getsize("test.txt")
# getsize("FILE")函式可以取得參數file的檔案大小,單位為byte
```
>Output
>> 148
### 8-5-5 刪除檔案
```python=
import os
file = "D:\\vitas\\test.txt"
if os.path.exists(file):
os.remove(file)
else:
print("此檔案不存在!")
```
### 8-5-6 建立目錄
```python=
import os
dir = "D:\\vitas\\dir1"
if not os.path.exists(dir):
os.mkdir(dir)
else:
print("此目錄已經存在!")
```
### 8-5-7 刪除目錄
```python=
import os
dir = "D:\\vitas\\dir1"
if os.path.exists(dir):
os.rmdir(dir)
else:
print("此目錄不存在!")
```
### 8-5-8 複製檔案
```python=
import shutil
shutil.copy("src", "dst")
# copy( )的回傳值是目的路徑
shutil.copy("test.txt", "D:\\vitas\\dir1\\test2.txt")
# 也可以將一個檔案內的資料複製到另一個檔案內
```
### 8-5-9 複製目錄
```python=
import shutil
shutil.copytree("src", "dst")
# copytree( )的回傳值是目的路徑
shitil.copytree("D:\\vitas\\dir1", "D:\\vitas\\dir2\\dir3")
```
### 8-5-10 搬移檔案或目錄
```python=
import shutil
shutil.move("src", "dst")
# copytree( )的回傳值是目的路徑
shutil.move("test.txt", "D:\\vitas\\dir1\\test2.txt")
# 將test.txt搬移到D:\vitas\dir1\test2.txt
shitil.move("D:\\vitas\\dir1", "D:\\vitas\\dir2\\dir3")
# 將D:\vitas\dir1搬移到D:\vitas\dir2\dir3
```
### 8-5-11 取得符合條件的檔案名稱
```python=
glob.glob("D:\\vitas\\*.txt")
# 在D:\vitas\目錄底下找到所有副檔名是.txt的檔案
```
>Output
>> ['D:\\vitas\\a1.txt', 'D:\\vitas\\a2.txt', 'D:\\vitas\\a3.txt', D:\\vitas\\b1.txt', 'D:\\vitas\\b2.txt', 'D:\\vitas\\f1.txt']
```python=
glob.glob("D:\\vitas\\a*.txt")
# 在D:\vitas\目錄底下找到所有檔名開頭是a且副檔名是.txt的檔案
```
>Output
>> ['D:\\vitas\\a1.txt', 'D:\\vitas\\a2.txt', 'D:\\vitas\\a3.txt']
```python=
glob.glob("D:\\vitas\\[a-c]*.txt")
# 在D:\vitas\目錄底下找到所有檔名開頭是a到c且副檔名是.txt的檔案
```
>Output
>> ['D:\\vitas\\a1.txt', 'D:\\vitas\\a2.txt', 'D:\\vitas\\a3.txt', D:\\vitas\\b1.txt', 'D:\\vitas\\b2.txt']
- <span class='red'>星號(*)為萬用字元,表示任意0個以上的字元</span>
- <span class='red'>[ ]表示任意在字元範圍中的任意字元,例如:[a-d]表示字元a, b, c, d</span>