elasticsearch入門系列">elasticsearch入門系列
824
2022-05-29
前言
如果我們要操作文件、目錄,可以在命令行下面輸入操作系統提供的各種命令來完成。比如 dir,cd 等命令。如果要在 Python 程序中執行這些目錄和文件的操作怎么辦?其實操作系統提供的命令只是簡單地調用了操作系統提供的接口函數,Python 內置的 os模塊也可以直接調用操作系統提供的接口函數。
os 模塊是 Python 標準庫中的一個用于訪問操作系統相關功能的模塊。
os 模塊的主要功能:系統相關、目錄及文件操作、執行命令和管理進程
Ps:其中的進程管理功能主要是 Linux 相關的,本節不做討論。
使用 os 模塊:
import os
在使用 os 模塊的時候,如果出現了問題,會拋出 OSError 異常,表明無效的路徑名或
文件名,或者路徑名(文件名)無法訪問,或者當前操作系統不支持該操作等。
>>> import os >>> os.chdir("d:") Traceback (most recent call last): File "
1. 系統相關
os 模塊提供了一些操作系統相關的變量,可以在跨平臺的時候提供支持,便于編寫移植性高,可用性好的代碼。所以在涉及操作系統相關的操作時,請盡量使用本模塊提供的方法,而不要使用當前平臺特定的用法或格式,否則一旦移植到其他平臺,可能會造成難以解決的困擾。
下面以表格的形式,列舉 os 模塊中常用的方法和變量,及其用途解釋。
使用范例:
2. 文件和目錄操作
os 模塊中包含了一系列文件操作相關的函數,其中有一部分是 Linux 平臺專用方法。Linux 是用 C 寫的,底層的 libc 庫和系統調用的接口都是 C API,Python 的 os 模塊中包括了對這些接口的 Python 實現,通過 Python 的 os 模塊,可以調用 Linux 系統的一些底層功能,進行系統編程。關于 Linux 的相關方法,可根據需要自行查閱官方文檔,這里只介紹一些常用的,各平臺通用的方法。
在 Python 中,使用 windows 的文件路徑時一定要小心,比如你要引用 d 盤下的 1.txt文件,那么路徑要以字符串的形式寫成’d:.txt’或者 r’d:.txt’。前面的方式是使用windwos 的雙斜杠作為路徑分隔符,后者是使用原生字符串的形式,以 r 開始的字符串都被認為是原始字符串,表示字符串里所有的特殊符號都以本色出演,不進行轉義,此時可以使用普通 windows 下的路徑表示方式。這兩種方法使用哪種都可以,但不可混用。
下面是一些使用的例子,建議大家都跟著做一遍(其中有一些是錯誤示范,讓你更清楚它的用法)。
>>> os.getcwd() #獲取當前目錄 'C:\Python36' >>> os.chdir("d:") #進入 D:目錄 >>> os.getcwd() 'D:\' >>> os.curdir #返回當前目錄 '.' >>> os.pardir #返回父目錄 '..' >>> os.makedirs("1\2") #創建目錄 >>> os.removedirs("1\2") 刪除目錄 >>> os.listdir() ['0Section', '$RECYCLE.BIN', '1.txt', 'MobileFile', 'pymysql_test.py', 'System Volume Information', '用戶目錄'] >>> os.mkdir("1") >>> os.listdir() ['0Section', '$RECYCLE.BIN', '1', '1.txt', 'MobileFile', 'pymysql_test.py', 'System Volume Information', '用戶目錄'] >>> os.rmdir("1") >>> os.rename('1.txt','2.txt') >>> os.listdir() ['0Section', '$RECYCLE.BIN', '2.txt', 'MobileFile', 'pymysql_test.py', 'System Volume Information', '用戶目錄'] >>> os.remove('1.txt') Traceback (most recent call last): File "
os.walk(top, topdown=True, onerror=None, followlinks=False)
walk 方法是 os 模塊中非常重要和強大的一個方法。可以幫助我們非常便捷地以遞歸方式自頂向下或者自底向上的方式遍歷目錄樹,對每一個目錄都返回一個三元元組(dirpath, dirnames, filenames)。
其中:
dirpath - 遍歷所在目錄樹的位置,是一個字符串對象
dirnames - 目錄樹中的子目錄組成的列表,不包括(".“和”…")
filenames - 目錄樹中的文件組成的列表
如果可選參數 topdown = True 或者沒有指定,則采用自頂向下的方式進行目錄遍歷,也就是從父目錄向子目錄逐步深入遍歷,如果 topdown = False,則采用自底向上的方式遍歷目錄,也就是先打印子目錄再打印父目錄的方式。
如果可選參數 onerror 被指定,則 onerror 必須是一個函數,該函數有一個 OSError 實例的參數,這樣可以允許在運行的時候即使出現錯誤的時候不會打斷 os.walk()的執行,或者拋出一個異常并終止 os.walk()的運行。通俗的講,就是定義這個參數用于指定當發生了錯誤時的處理方法。
默認情況下,os.walk()遍歷的時候不會進入符號鏈接,如果設置了可選參數followlinks = True,則會進入符號鏈接。注意,這可能會出現遍歷死循環,因為符號鏈接可能會出現自己鏈接自己的情況,而 os.walk()沒有那么高的智商,無法發現這一點。
下面的例子會將 c:\python36 目錄中的所有文件和子目錄打印出來。
import os try: for root, dirs, files in os.walk(r"c:\python36"): print("directory", root) for directory in dirs: print("
下面的例子會統計 c:/python36/Lib/email 目錄下所有子目錄的大小,但是 CVS 目錄除外。
import os from os.path import join, getsize for root, dirs, files in os.walk('c:/python36/Lib/email'): print(root, "consumes", end=" ") print(sum(getsize(join(root, name)) for name in files), end=" ") print("bytes in", len(files), "non-directory files") if 'CVS' in dirs: dirs.remove('CVS') # 不遍歷 CVS 目錄
運行結果:
C:\Python36\python.exe F:/Python/pycharm/201705/1.py - c:/python36/Lib/email consumes 377849 bytes in 21 non-directory files c:/python36/Lib/email\mime consumes 12205 bytes in 9 non-directory files c:/python36/Lib/email\mime\__pycache__ consumes 30289 bytes in 27 nondirectory files c:/python36/Lib/email\__pycache__ consumes 741924 bytes in 60 non-directory files
下面的例子會遞歸刪除目錄的所有內容,危險,請勿隨意嘗試!
import os for root, dirs, files in os.walk(top, topdown=False): for name in files: os.remove(os.path.join(root, name)) for name in dirs: os.rmdir(os.path.join(root, name))
3. 執行命令
我們幾乎可以在任何操作系統上通過命令行指令與操作系統進行交互。那么我們如何通過 Python 來完成這些命令行指令的執行呢?首先,我們應該知道的是命令行指令的執行通常有兩個我們比較關注的結果:
命令執行的狀態碼–表示命令執行是否成功
命令執行的輸出結果–命令執行成功后的輸出
早期的 Python 版本中,我們主要是通過 os.system()、os.popen().read()等函數來執行命令行指令的,另外還有一個很少使用的 commands 模塊。但是從 Python 2.4 開始官方文檔中建議使用的是 subprocess 模塊,所以 os 模塊和 commands 模塊的相關函數在這里只提供一個簡單的使用示例,我們重要要介紹的是 subprocess 模塊。
os.system(command)
運行操作系統命令,直接顯示結果。但返回值是 0 或-1,不能獲得顯示在屏幕上的數據。 command 是要執行的命令字符串。
如果我們是在 windows 環境下使用 IDLE 運行 os.system(‘ipconfig /all’),你會發現命令終端界面一閃而過,根本啥都來不及看。這時候,你最好進入 cmd 環境使用 python命令進入交互式界面才可以看到屏幕上的信息。
由于使用該函數經常會莫名其妙地出現錯誤,但是直接執行命令并沒有問題,所以一般建議不要使用。
os.popen(command, [mode, [bufsize]])
開啟一個子進程執行 command 參數指定的命令,在父進程和子進程之間建立一個管道 pipe,用于在父子進程間通信。該方法返回一個文件對象,可以對這個文件對象進行讀或寫,取決于參數 mode,如果 mode 指定了只讀,那么只能對文件對象進行讀,如果 mode 參數指定了只寫,那么只能對文件對象進行寫操作。
簡而言之,popen 也可以運行操作系統命令,并通過 read()方法將命令的結果返回,不像 system 只能看不能存,這個能存!
>>> os.popen('ipconfig')
subprocess 模塊
subprocess 模塊主要用于創建子進程,并連接它們的輸入、輸出和錯誤管道,獲取它們的返回狀態。通俗地說就是通過這個模塊,你可以在 Python 的代碼里執行操作系統級別的命令,比如“ipconfig”等等。
subprocess 模塊中的常用函數
大多數情況下,推薦使用 run()方法調用子進程,執行操作系統命令。
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False, encoding=None, errors=None)
功能:執行 args 參數所表示的命令,等待命令結束,并返回一個CompletedProcess 類型對象。
注意,run()方法返回的不是我們想要的執行結果或相關信息,而是一個CompletedProcess 類型的對象。
上面參數表里展示的只是一些常用的,真實情況還有很多。
args:表示要執行的命令。必須是一個字符串,字符串參數列表
stdin、stdout 和 stderr:子進程的標準輸入、輸出和錯誤。其值可以是subprocess.PIPE、subprocess.DEVNULL、一個已經存在的文件描述符、已經打開的文件對象或者 None。subprocess.PIPE 表示為子進程創建新的管道。
subprocess.DEVNULL 表示使用 os.devnull。默認使用的是 None,表示什么都不做。另外,stderr 可以合并到 stdout 里一起輸出。
timeout:設置命令超時時間。如果命令執行時間超時,子進程將被殺死,并彈出TimeoutExpired 異常。
check:如果該參數設置為 True,并且進程退出狀態碼不是 0,則彈出CalledProcessError 異常。
encoding:如果指定了該參數,則 stdin、stdout 和 stderr 可以接收字符串數據,并以該編碼方式編碼。否則只接收 bytes 類型的數據。
shell:如果該參數為 True,將通過操作系統的 shell 執行指定的命令。
run()方法的返回值,表示一個進程結束了。
CompletedProcess 類有下面這些屬性:
args 啟動進程的參數,通常是個列表或字符串。
returncode 進程結束狀態返回碼。0 表示成功狀態。
stdout 獲取子進程的 stdout。通常為 bytes 類型序列,None 表示沒有捕獲值。如果你在調用run()方法時,設置了參數 stderr=subprocess.STDOUT,則錯誤信息會和 stdout 一起輸出,此時 stderr
的值是 None。
stderr 獲取子進程的錯誤信息。通常為 bytes 類型序列,None 表示沒有捕獲值。
check_returncode() 用于檢查返回碼。如果返回狀態碼不為零,彈出CalledProcessError 異常。
subprocess.DEVNULL
一個特殊值,用于傳遞給 stdout、stdin 和 stderr 參數。表示使用 os.devnull 作為參數
值。
subprocess.PIPE
管道,可傳遞給 stdout、stdin 和 stderr 參數。
subprocess.STDOUT
特殊值,可傳遞給 stderr 參數,表示 stdout 和 stderr 合并輸出。
args 與 shell 參數
args 參數可以接收一個類似’dir d:\'的字符串,也可以傳遞一個類似[‘dir’, ‘d:\’]的字符串分割列表。shell 參數默認為 False,設置為 True 的時候表示使用操作系統的 shell 執行命令。下面我們來看一下兩者的組合結果。
到 windows 系統中測試一下,分別獨立執行下面的語句:
ret = subprocess.run('dir d:\\') ret = subprocess.run('dir d:\\', shell=True) ret = subprocess.run(['dir', 'd:\\']) ret = subprocess.run(['dir', 'd:\\'], shell=True) ret = subprocess.run('ipconfig /all') ret = subprocess.run('ipconfig /all', shell=True) ret = subprocess.run(['ipconfig', '/all']) ret = subprocess.run(['ipconfig', '/all'], shell=True)
結果表明,在 windows 中,args 和 shell 參數組合比較復雜,根據命令的不同有不同的情況。建議 shell 設置為 True。
獲取執行結果
run()方法返回的是一個 CompletedProcess 類型對象,不能直接獲取我們通常想要的結果。要獲取命令執行的結果或者信息,在調用 run()方法的時候,請指定
stdout=subprocess.PIPE。 >>> ret = subprocess.run('dir', shell=True) >>> ret CompletedProcess(args='dir', returncode=0) >>> ret = subprocess.run('dir', shell=True, stdout=subprocess.PIPE) >>> ret CompletedProcess(args='dir', returncode=0, stdout=b' \xc7\xfd\xb6\xaf\xc6\xf7 ......') >>> ret.stdout b' \xc7\xfd\xb6\xaf\xc6\xf7 C \xd6\xd0\xb5\xc4\xbe\xed\xca\xc7 ......' >>> ret.stdout.decode('gbk') ' 驅動器 C 中的卷是 系統\r\n 卷的序列號是 C038-3181\r\n\r\n C:\\Python36 的目錄 \r\n\r\n2017/08/11 10:14 ...... 15,275,020,288 可用字節\r\n'
從例子中我們可以看到,如果不設置 stdout=subprocess.PIPE,那么在返回值CompletedProcess(args=‘dir’, returncode=0)中不會包含 stdout 屬性。反之,則會將結果以 bytes 類型保存在 ret.stdout 屬性中。注意: 中文 windows 系統使用 GBK 編碼,需要 decode(‘gbk’)才可以看見熟悉的中文。
交互式輸入
并不是所有的操作系統命令都像‘dir’或者‘ipconfig’那樣單純地返回執行結果,還有很多像‘python’這種交互式的命令,你要輸入點什么,然后它返回執行的結果。使用 run()方法怎么向 stdin 里輸入?
參考下面的使用方法, 在一個 1.txt 文件中寫入 print(‘i like Python’),然后:
import subprocess fd = open("d:\\1.txt") ret = subprocess.run("python", stdin=fd, stdout=subprocess.PIPE,shell=True) print(ret.stdout) fd.close()
這樣做,雖然可以達到目的,但是很不方便,也不是以代碼驅動的方式。這個時候,我們可以使用 Popen 類。
subprocess.Popen()類
用法和參數與 run()方法基本類同,但是它的返回值是一個 Popen 對象,而不是CompletedProcess 對象。
>>> ret = subprocess.Popen("dir", shell=True) >>> type(ret)
要實現前面的‘python’命令功能,可以按下面的例子操作:
import subprocess s = subprocess.Popen("python", stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=True) s.stdin.write(b"import os\n") s.stdin.write(b"print(os.environ)") s.stdin.close() out = s.stdout.read().decode("GBK") s.stdout.close() print(out)
通過 s.stdin.write()可以輸入數據,而 s.stdout.read()則能輸出數據。
5G教育 Python
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。