Python下OS操作(路徑、讀寫、引用、字符串操作)

路徑問題

目錄增刪

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章