路徑問題
目錄增刪
import os, shutil
os.mkdir(path) #創建單級目錄
os.makedirs(path) #創建多級目錄(目標目錄及其父目錄均未創建時,使用該命令可一同創建,mkdir則不行)
os.rmdir(path) #刪除一個空文件夾(目錄),非空會報錯
print(os.getcwd()) #打印當前工作所處目錄
os.chdir(path) #更改當前工作所處目錄
shutil.rmtree(path) #刪除目錄及目錄內所有文件
引用文件
打開與代碼在同一文件夾下(與代碼同級)的文件:
#This code file is named "open_img.py"
from PIL import Image
path = 'img.jpg'
img=Image.open(path)
img.show()
也可以寫成:
path = './img.jpg'
./表示當前目錄,一般可省略不寫
打開代碼同級文件夾下的文件:
path = 'a/img.jpg'
同理,也可以寫成:
path = './a/img.jpg'
若文件夾a中還有多級文件夾,繼續加“/”深化路徑即可。
打開代碼文件上級文件夾中的文件:
path = '../img.jpg'
../表示上級目錄,若img.jig還在更上層,可以繼續疊加../
以上可以綜合運用,例如a、b文件夾同級,代碼在a中,圖片在b中:
path = '../b/img.jpg'
若圖片在硬盤根目錄:
path = '/img.jpg'
圖片絕對路徑爲:C:/img.jpg
以上寫法均爲相對路徑寫法,Python同樣支持寫絕對路徑。
注意:在Windows中,文件的從屬關係用“\”表示,然而在Python中該符號爲轉義符號,因此在表示路徑時用“/”或“\\”表示。(非Windows系統如Linux本身就用“/”表示)。然而如果將路徑輸出,可能會看到“\\”、“\”和“/”共存的情況,這個不影響,只要代碼中使用“/”或“\\”即可。
獲取當前文件的位置
import os
print(os.getcwd())
print(os.path.dirname(__file__))
print(os.path.realpath(__file__))
在某個文件(假設爲a.py)輸入以上代碼,輸出爲:
C:\Users\Zerg Wang\Desktop
C:/Users/Zerg Wang/Desktop
C:\Users\Zerg Wang\Desktop\a.py
可以看到同樣的路徑相同,不同函數分別以“\”和“/”區分,這個無影響。
完整路徑下分離路徑、文件名、拓展名:
import os
st = '1/2/3/4/5.jpg'
print(os.path.split(st)) # ('1/2/3/4', '5.jpg')
print(os.path.splitext(st)) # ('1/2/3/4/5', '.jpg')
os.path.split返回兩個值,第一個爲字符串st的路徑,第二個爲文件名。
注意,該函數也可對目錄使用,假如目錄名爲4,完整路徑爲1/2/3/4,則返回1/2/3和4。
os.path.splitext也返回兩個值,第一個爲文件名(無後綴名),第二個爲後綴名(包括“.”)
可用索引指定第一個或第二個值,如:
filename = os.path.splitext(st)[0]
extensionname = os.path.splitext(st)[1]
獲取文件夾下所有文件名
os.listdir(dir_path)
返回一個list,由文件夾下所有文件和文件夾的名字(僅文件名,無路徑)構成。遍歷的深度僅爲1,也就是說,如果其內部文件夾中還有文件,這些文件不會被遍歷到。
如果要遍歷包括所有子文件夾中的內容(深度不限),則使用os.walk(dir_path),返回三個值:root,dirs,files,其中root爲當前遍歷的目錄地址,dirs爲list,存有所有子目錄,files也爲list,存有所有文件(不包括子目錄),若要得到這些值,可以:
for root, dirs, files in os.walk(folder):
print(root)
for dir in dirs:
print(dir) #輸出所有子目錄名(不含路徑)
for f in files:
print(f) #輸出所有文件名(不含路徑)
外層的for循環是控制遍歷深度的,也就是說,如果按以上代碼運行,第一次循環,遍歷深度爲1,會輸出folder的目錄名(root)、folder下的子目錄名和folder下的文件名,然後第二次循環,遍歷深度爲2,會分別輸出folder下的子目錄名及該子目錄下的子目錄名和文件,一次類推……舉個例子:
假如folder目錄下結構如上圖所示,則按上述代碼,輸出爲:
C:/Users/Zerg Wang/Desktop/PythonEnv #遍歷深度爲1時的root
.vscode
Images #先輸出root下僅一層的子目錄
1.png
2.png
a.py #再輸出root下僅一層的文件
C:/Users/Zerg Wang/Desktop/PythonEnv\.vscode #遍歷深度爲2時的root
launch.json
settings.json
C:/Users/Zerg Wang/Desktop/PythonEnv\Images #遍歷深度爲2時的root
agricultural
airplane
C:/Users/Zerg Wang/Desktop/PythonEnv\Images\agricultural #遍歷深度爲3時的root
agricultural00.tif
agricultural01.tif
C:/Users/Zerg Wang/Desktop/PythonEnv\Images\airplane #遍歷深度爲3時的root
airplane00.tif
airplane01.tif
glob
Python自帶的庫,無需pip安裝,功能類似於Windows中的搜索,其函數glob.glob(path)通過在path中插入通配符*或?起到搜索的功能,返回爲一個列表,包含所有符合的結果路徑。除了常用的glob.glob,還有glob.iglob,兩者功能類似,後者返回迭代器。
以VOC數據集的路徑爲例:
import glob
for path in glob.glob('VOCdevkit/*/*'):
print(path)
(此爲部分截圖,返回的路徑格式與輸入路徑一致)
再介紹一下通配符,“*”用於匹配0到多個字符,例如*.jpg就是所有擴展名爲jpg的文件,而“?”僅匹配一個字符,例如“VOC20??”輸出爲“VOC2007”和“VOC2012”,此外在匹配時還可以指定字符,例如[0-9]指定的就是單個數字字符。
如果輸入的路徑精確到某一文件,則輸出該文件路徑。
文件讀寫
正常讀取及打印文件內容:
f = open(path,'r')
print(f.read()) #f.readline() or f.readlines()
f.close() #一般要在最後關閉文件的讀寫,防止其持續佔用計算機資源。
'r'表示文件爲只讀模式。
f.read():一次性讀取文件全部內容。
f.readline():每次讀取文件中的一行。
f.readlines():同樣是讀取全部內容,但以list形式返回。
以上方法可接參數,表示每次讀取的字節數,因此以上方法可迭代使用。
文件寫入:
f = open(path,'w') #若文件不存在會自動創建
如果寫入方式是在文件末尾追加內容,則爲:
f = open(path,'a') #若文件不存在會自動創建
使用f.write('context...')即可向文件內寫入內容。
如果要使文件可在程序中既能被讀也能被寫:模式可以設置爲'r+'、'w+'、'a+‘。
文件讀寫的進度靠一個指針控制,讀取共用,也就是說,要實現'a'模式,可以先:
f = open(path,'r+')
f.read()
把文件原有內容先讀出,指針就會在文件末尾,從而進行內容的追加。
要知道當前指針位置,可用file.tell(),返回一個數字,表示指針前的字節數。
注意:’r+'和'w+'模式是有區別的,'w'和'w+'模式會先將文件原有內容覆蓋。
圖片來自菜鳥教程(http://www.runoob.com/python/python-files-io.html)
二進制形式讀寫:
在對應的模式下加上'b'即可,例如:
f1 = open(path,'rb')
f2 = open(path,'wb')
f3 = open(path,'ab')
With...as讀寫方式
爲防止文件讀寫過程中出錯中止程序以至於f.close()未能執行,一般會使用try...finally保證文件被正常關閉:
try:
f = open(path, 'r')
print(f.read())
finally:
if f:
f.close()
當然,使用with...as會更加簡潔:(雖然沒寫出來,但無論程序是否中斷f.close仍會執行)
with open(path, 'r') as f:
print(f.read())
刪除與重命名
import os
os.rename(old_path, new_path)
os.remove(path)
複製與移動
import shutil
shutil.move(file_path, target_path) #文件移動
shutil.copy(file_path, target_path) #文件複製
目標路徑target_path最後有沒有“/”無所謂~
shutil.copyfile功能與shutil.copy相似,但使用前者可能會遇到權限問題,因此推薦後者。
前面的file_path也可以填寫目錄名,但shutil.copy複製目錄可能會遇到權限問題……
特殊數據類型與文件的交互
字典、列表的內容若要存儲於文件,或從文件中讀取(代碼中的d可以是列表,也可以是字典):
#保存
f = open('file.txt','w')
f.write(str(d))
f.close()
#讀取
f = open('file.txt','r')
d = eval(f.read())
f.close()
在file.txt中,數據保存的格式與print該列表(或字典)的格式一致。
Python包引用
同文件夾下的a.py要引用b.py:
#This code file is named "a.py"
from . import b
導入Python包時的簡寫
import numpy as np, pandas
以上代碼的意思不是numpy有兩個別名,而是import了numpy和pandas,其中numpy的簡寫爲np,可以:
import numpy as np, pandas as pd