目錄node
使用Python操做文件系統時,少不了會對路徑進行切換,對目錄的遍歷,以及獲取文件的絕對路徑的一系列的操做,Python內置了相關的模塊完成對應的功能,其中:python
os.path是os模塊中的一個比較重要的用來拼接、判斷路徑的主要方法,它主要有以下方法:mysql
os.path.abspath('dir/file') 獲取dir/file的絕對路徑 os.path.split('path') 把路徑分割爲目錄和文件名組成的元組格式,無論path是否存在 os.dirname('path') 獲取文件的父目錄名稱,無論path是否存在 os.basename('path') 獲取文件的名稱,無論path是否存在 os.path.exists('path') 判斷path是否存在,return bool os.path.isabs('path') 判斷path是不是從根開始,return bool os.path.isfile('path') 判斷path是不是一個文件 os.path.isdir('path') 判斷path是不是一個目錄 os.path.join('path1','path2','path3'):把path1和path2及path3進行組合,但若是path2中包含了根路徑,那麼就會捨棄path1,從path2開始組合 os.path.getatime('path') 獲取文件的atime時間,返回時間戳 os.path.getmtime('path') 獲取文件的mtime時間,返回時間戳 os.path.getsize(filename) 獲取文件的大小,單位是字節
Linux下:從/開始,Windows下從C,D,E盤開始nginx
In [1]: import os In [2]: os.path.join('/etc','sysconfig','network-scripts') Out[2]: '/etc/sysconfig/network-scripts' In [3]: os.path.join('/etc','/sysconfig','network-scripts') Out[3]: '/sysconfig/network-scripts' In [8]: p = os.path.join('/etc','sysconfig','network-scripts') In [9]: p Out[9]: '/etc/sysconfig/network-scripts' In [10]: type(p) Out[10]: str In [12]: os.path.exists(p) Out[12]: True In [13]: os.path.split(p) Out[13]: ('/etc/sysconfig', 'network-scripts') In [14]: os.path.abspath('.') Out[14]: '/home/python/py368' In [16]: os.path.dirname(p) Out[16]: '/etc/sysconfig' In [17]: os.path.basename(p) Out[17]: 'network-scripts' >>> os.path.splitdrive('c:/etc/sysconfig/network-script') # windows ('c:', '/etc/sysconfig/network-script')
__file__:變量比較特殊,存放的是當前的Python文件的名稱,咱們可使用os.path.abspath(file)來獲取當前python文件的絕對路徑,而後進行打包或者進行相對調用。sql
3.4之後建議使用pathlib模塊,它提供Path對象來對路徑進行操做,還包括了目錄和文件。windows
在使用時須要實現導入: from pathlib import Pathapp
下面來講一下平常的目錄相關操做less
經過構建一個Path對象來對路徑進行初始化socket
In [19]: from pathlib import Path In [20]: p = Path() # 當前目錄 In [21]: p1 = Path('a','b','c') # 當前目錄下的a/b/c In [22]: p2 = Path('/etc','sysconfig','network-scripts') # /etc/sysconfig/network-scripts In [23]: p Out[23]: PosixPath('.') In [24]: p1 Out[24]: PosixPath('a/b/c') In [25]: p2 Out[25]: PosixPath('/etc/sysconfig/network-scripts')
/
: Path對象支持使用/
來進行路徑的拼接,拼接規則應遵循:函數
In [30]: p2 / 'ifcfg-eth0' Out[30]: PosixPath('/etc/sysconfig/network-scripts/ifcfg-eth0') In [35]: p2 / p1 Out[35]: PosixPath('/etc/sysconfig/network-scripts/a/b/c') In [37]: '/root' / p2 Out[37]: PosixPath('/etc/sysconfig/network-scripts')
須要注意的是:
parts屬性
: 將Path對象按照當前操做系統的分隔符進行分割返回一個元組
In [39]: p2.parts Out[39]: ('/', 'etc', 'sysconfig', 'network-scripts')
joinpath(*other)
: 在Path對象中使用當前操做系統的路徑分隔符分割並追加多個字符串。
In [43]: p2.joinpath('/etc') Out[43]: PosixPath('/etc') In [44]: p2.joinpath('etc') Out[44]: PosixPath('/etc/sysconfig/network-scripts/etc') In [50]: p2.joinpath('/etc','/proc') Out[50]: PosixPath('/proc')
須要注意的是:
Path返回的是一個路徑對象,那麼如何才能夠只打印路徑的字符串格式呢,咱們能夠經過str(Path對象)
進行轉換,當須要bytes格式時,也可使用bytes(Path對象)
轉換。
In [51]: bytes(p2) Out[51]: b'/etc/sysconfig/network-scripts' In [52]: str(p2) Out[52]: '/etc/sysconfig/network-scripts'
parent
: 當前目錄的邏輯父目錄
parents
: 因此父目錄的序列,索引0時爲當前目錄的父目錄,依次類推
In [53]: p2.parent Out[53]: PosixPath('/etc/sysconfig') In [54]: p2.parent.parent Out[54]: PosixPath('/etc') In [55]: p2.parent.parent.parent # 鏈式操做 Out[55]: PosixPath('/') In [57]: p2.parents Out[57]: <PosixPath.parents> # 可迭代對象 In [58]: list(p2.parents) Out[58]: [PosixPath('/etc/sysconfig'), PosixPath('/etc'), PosixPath('/')] In [59]:
parent屬性,看似支持類js的鏈式操做,主要仍是由於每次使用parent屬性時,返回的仍是一個Path對象,因此才能夠一直parent下去。
在一個目錄的絕對路徑中咱們可能會單獨使用目錄的名稱、目錄的後綴名等等,Path對象提供了專門的屬性及方法便於獲取或者對它們進行修改。
name
: 目錄的最後一個部分suffix
:目錄中最後一個部分的擴展名stem
:目錄中最後一個部分,不包含後綴名suffixes
: 多個後綴名造成的列表In [1]: from pathlib import Path In [2]: p = Path('/tmp/mysql.tar.gz') In [3]: p.name Out[3]: 'mysql.tar.gz' In [4]: p.suffix Out[4]: '.gz' In [5]: p.stem Out[5]: 'mysql.tar' In [6]: p.suffixes Out[6]: ['.tar', '.gz']
with_suffix(suffix)
: 有擴展名則替換,無則補充擴展名(注意後綴名要加點)with_name(name)
:替換目錄最後一個部分並返回一個新的路徑In [9]: p Out[9]: PosixPath('/tmp/mysql.tar.gz') In [10]: p.with_suffix('.abc') Out[10]: PosixPath('/tmp/mysql.tar.abc') In [11]: p1 = Path('/tmp/nginx') In [12]: p1.with_suffix('.abc') Out[12]: PosixPath('/tmp/nginx.abc') In [15]: p Out[15]: PosixPath('/tmp/mysql.tar.gz') In [16]: p.with_name('nginx.tar.gz') Out[16]: PosixPath('/tmp/nginx.tar.gz')
cwd()
: 返回當前工做目錄home()
: 返回當前家目錄is_dir()
: 是不是目錄,是目錄且存在,則返回Trueis_file()
: 是不是普通文件,是文件且存在,則返回Trueis_symlink()
: 是不是阮連接is_socket()
: 是不是socket文件is_block_device()
: 是不是塊設備is_char_device()
: 是不是字符設備is_absolute()
: 是不是絕對路徑In [34]: p = Path('/etc','sysconfig') In [35]: p2 = Path('/etc','hosts') In [36]: p3 = Path('/etc','rc.d','rc3.d','S10network') In [37]: p.is_dir() Out[37]: True In [38]: p1.is_file() Out[38]: False In [39]: p2.is_file() Out[39]: True In [44]: p3.is_symlink() Out[44]: True In [45]: p.is_absolute() Out[45]: True
resolve()
: 返回當前Path對象的絕對路徑。若是是軟鏈接,則直接被解析absolute()
: 獲取Path對象的絕對路徑In [28]: p3 = Path('hosts') In [29]: p3 Out[29]: PosixPath('hosts') In [30]: p3.resolve() # 軟連接的真正路徑 Out[30]: PosixPath('/etc/hosts') In [31]: p3.absolute() # 軟連接的絕對路徑 Out[31]: PosixPath('/home/python/py368/hosts')
exists()
: 文件或者目錄是否存在rmdir()
: 刪除空目錄(沒有提供目錄爲空的方法)touch(mode=0o666,exist_ok=False)
: 建立一個文件
mode
: 文件的屬性,默認爲666exist_ok
: 在3.5版本加入,False時,路徑存在,拋出FileExistsError;True時,異常將被忽略In [47]: p = Path('/tmp','hello.py') In [49]: p.exists() Out[49]: False In [50]: p.touch(mode=0o666,exist_ok=False) In [51]: p.exists() Out[51]: True In [52]: p.touch(mode=0o666,exist_ok=False) --------------------------------------------------------------------------- FileExistsError Traceback (most recent call last) ... FileExistsError: [Errno 17] File exists: '/tmp/hello.py' In [53]:
In [56]: p2.as_uri() Out[56]: 'file:///etc/hosts'
mkdir(mode=0o777,parents=False,exist_ok=False)
: 建立一個目錄
parents
:是否建立父目錄,True等同於mkdir -p
, False時,父目錄不存在曝出FileNotFoundErrorexist_ok
: 在3.5版本加入,False時,路徑存在,拋出FileExistsError;True時,異常將被忽略iterdir()
: 迭代當前目錄,不遞歸。In [74]: for x in p4.parents[0].iterdir(): ...: if x.is_dir(): ...: flag = False ...: for _ in x.iterdir(): ...: flag = True ...: break ...: print('dir: {} , is {}'.format(x,'not empty ' if flag else 'empt ...: y' )) ...: elif x.is_file(): ...: print('{} is a file'.format(x)) ...: else: ...: print('other file')
判斷文件類型,當文件爲目錄時,判斷其是否爲空目錄。
glob(partten)
: 在目錄下
通配給定的格式rglob(partten)
: 在目錄下
遞歸通配給定的格式(遞歸目錄)match(partten)
: 模式匹配(對當前Path對象進行匹配),成功返回TrueIn [84]: p4 Out[84]: PosixPath('/etc/sysconfig/network-scripts') In [85]: list(p4.glob('ifu?-*')) Out[85]: [PosixPath('/etc/sysconfig/network-scripts/ifup-aliases'), PosixPath('/etc/sysconfig/network-scripts/ifup-bnep'), PosixPath('/etc/sysconfig/network-scripts/ifup-eth'), PosixPath('/etc/sysconfig/network-scripts/ifup-ippp'), PosixPath('/etc/sysconfig/network-scripts/ifup-ipv6'), PosixPath('/etc/sysconfig/network-scripts/ifup-isdn'), PosixPath('/etc/sysconfig/network-scripts/ifup-plip'), PosixPath('/etc/sysconfig/network-scripts/ifup-plusb'), PosixPath('/etc/sysconfig/network-scripts/ifup-post'), PosixPath('/etc/sysconfig/network-scripts/ifup-ppp'), PosixPath('/etc/sysconfig/network-scripts/ifup-routes'), PosixPath('/etc/sysconfig/network-scripts/ifup-sit'), PosixPath('/etc/sysconfig/network-scripts/ifup-tunnel'), PosixPath('/etc/sysconfig/network-scripts/ifup-wireless'), PosixPath('/etc/sysconfig/network-scripts/ifup-ib'), PosixPath('/etc/sysconfig/network-scripts/ifup-Team'), PosixPath('/etc/sysconfig/network-scripts/ifup-TeamPort')] In [87]: p4.match('/etc/*/network-script?') Out[87]: True
stat()
: 查看目錄的詳細信息,至關於stat命令lstat()
: 若是是符號連接,則顯示符號連接自己的文件信息In [88]: p4.stat() Out[88]: os.stat_result(st_mode=16877, st_ino=67533402, st_dev=2050, st_nlink=2, st_uid=0, st_gid=0, st_size=4096, st_atime=1550229289, st_mtime=1545830238, st_ctime=1545830238)
Path對象一樣提供了打開文件的函數,功能相似於內建函數open。返回一個文件對象。當咱們建立一個Path對象時,這個文件已經被打開,當咱們寫入數據時,文件不存在會新建,重名或者是目錄,會有相應的異常提示,它的語法是
Path.open(mode='r',buffering=-1,encoding=None,errors=None,newline=None)
例:
In [115]: p5 Out[115]: PosixPath('/tmp/123') In [116]: p = p5.open(mode='r') In [117]: p Out[117]: <_io.TextIOWrapper name='/tmp/123' mode='r' encoding='UTF-8'> In [118]: p.read() Out[118]: '123' In [119]: p5.read_text() # 不存在時報異常,存在則直接打開並讀取 Out[119]: '123'
3.5之後新增長的函數方法:
Path.read_bytes()
: 以'rb'方式讀取路徑對應文件,並返回二進制流。Path.read_text()
: 以'rt'方式讀取路徑文件, 並返回文件。無視指針Path.write_bytes()
: 以'wb'方式寫入數據到路徑對應文件中。Path.write_text()
: 以'wt'方式寫入數據到路徑對應文件中。os模塊的經常使用方法:
os.getcwd(): 獲取當前路徑 os.chdir(): 切換當前目錄,當路徑中存在\的時候,因爲是轉意的意思,那麼就須要對\進行轉意,那麼路徑就是c:\\User,或者在目錄前面加r,表示後面的字符串不進行解釋 os.curdir(): 獲取當前目錄名 os.pardir(): 獲取上級目錄名 os.mkdir('dir'): 建立目錄,注意只能建立一級目錄 os.makedirs('dir_path'):建立多級目錄 os.rmdir('dir'): 刪除一個目錄 os.removedir('dir_path'):刪除多級目錄(目錄爲空的話) os.listdir('dir'): 顯示目錄下的全部文件,默認爲當前目錄,返回的結果爲list os.remove('file'): 刪除一個文件 os.rename('old_name','new_name'):修改文件名稱 os.stat('file/dir'):獲取文件/目錄的stat信息(調用的是系統的stat) os.sep: 返回當前操做系統的路徑分隔符(Windows下:\\ , Linux下:/) os.linesep: 返回當前操做系統的換行符(Windows下:\r\n ,Linux下:\n) os.pathsep: 返回當前操做系統環境變量分隔符(Windows下是; ,Linux下是:) os.name: 返回當前系統的類型(nt 表示Windows, posix表示Linux) os.system('Commmand'):執行命令 os.environ: 獲取系統環境變量,使用字典存儲 os.path.abspath('dir/file'):獲取dir/file的絕對路徑 os.path.split('path'):把路徑分割爲目錄和文件名組成的元組格式,無論path是否存在 os.dirname('path'):獲取文件的父目錄名稱,無論path是否存在 os.basename('path'):獲取文件的名稱,無論path是否存在
os.stat(follow_symlinks=True),返回源文件自己信息,False時,顯示連接文件的信息,對於軟鏈接自己,還可使用os.lstat方法
In [133]: os.lstat('hosts') Out[133]: os.stat_result(st_mode=41471, st_ino=2083428, st_dev=2050, st_nlink=1, st_uid=1001, st_gid=1001, st_size=10, st_atime=1550259162, st_mtime=1550259161, st_ctime=1550259161) In [134]: os.stat('hosts') Out[134]: os.stat_result(st_mode=33188, st_ino=67245317, st_dev=2050, st_nlink=1, st_uid=0, st_gid=0, st_size=158, st_atime=1550229294, st_mtime=1370615492, st_ctime=1545666279) In [136]: os.stat('hosts',follow_symlinks=False) # 等同於os.lstat() Out[136]: os.stat_result(st_mode=41471, st_ino=2083428, st_dev=2050, st_nlink=1, st_uid=1001, st_gid=1001, st_size=10, st_atime=1550259162, st_mtime=1550259161, st_ctime=1550259161) In [137]:
根據前面所學的知識,咱們若是想要進行文件拷貝,須要先打開兩個文件對象對象,源文件讀取內容,寫入到目標文件中去。 這種方式雖然完成了文件的拷貝,可是卻丟失了文件的屬性信息,好比屬組、權限等,由於咱們根本沒有進行復制。因此,python提供了一個用於高級文件操做的庫,它的名字就叫作shutil。
shutil.copyfileobj(fsrc,fdes,length)
: 將文件內容拷貝到另外一個文件中,能夠只拷貝部份內容,須要咱們自行打開文件對象進行copy,length表示buffer的大小,須要注意的是fdes必須可寫>>> import os,shutil >>> os.system('ls') 1.txt >>> shutil.copyfileobj(open('1.txt'),open('2.txt','w')) >>> os.system('ls') 1.txt 2.txt >>>
shutil.copyfile(fsrc,fdes)
: 複製文件,咱們只須要傳入文件名稱便可進行復制,不用自行預先打開,等於建立一個新的文件,把老文件寫入到新文件中而後關閉,新建立的文件權限和屬主等信息遵循操做系統規定(本質上仍是調用copyfileobj)>>> shutil.copyfile('1.txt','3.txt') >>> os.system('ls') 1.txt 2.txt 3.txt
shutil.copymode(src,des)
: 複製文件權限,既把src文件的權限複製給 des文件,只改變權限,不改變其餘好比屬組,內容等(des文件必須存在)>>> os.system('ls -l') total 12 -rwxrwxrwx 1 root root 6 Mar 9 18:35 1.txt -rw-r--r-- 1 root root 6 Mar 9 18:36 2.txt -rw-r--r-- 1 root root 6 Mar 9 18:38 3.txt >>> shutil.copymode('1.txt','2.txt') >>> os.system('ls -l') total 12 -rwxrwxrwx 1 root root 6 Mar 9 18:35 1.txt -rwxrwxrwx 1 root root 6 Mar 9 18:36 2.txt -rw-r--r-- 1 root root 6 Mar 9 18:38 3.txt >>>
shutil.copystat(src,des)
: 複製文件的權限,還包括,atime,mtime,flags等信息,不改變文件內容(des需存在)>>> os.system('stat 1.txt') File: `1.txt' Size: 6 Blocks: 8 IO Block: 4096 regular file Device: fd00h/64768d Inode: 926326 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2017-03-09 18:36:59.223738919 +0800 Modify: 2017-03-09 18:35:23.148738381 +0800 Change: 2017-03-09 18:39:59.061738605 +0800 >>> os.system('stat 3.txt') File: `3.txt' Size: 6 Blocks: 8 IO Block: 4096 regular file Device: fd00h/64768d Inode: 940237 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2017-03-09 18:39:42.214738376 +0800 Modify: 2017-03-09 18:38:13.862738316 +0800 Change: 2017-03-09 18:38:13.862738316 +0800 >>> shutil.copystat('1.txt','3.txt') >>> os.system('stat 3.txt') File: `3.txt' Size: 6 Blocks: 8 IO Block: 4096 regular file Device: fd00h/64768d Inode: 940237 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2017-03-09 18:36:59.223738000 +0800 Modify: 2017-03-09 18:35:23.148738000 +0800 Change: 2017-03-09 18:44:33.286738354 +0800 >>>
shutil.copy(src,des)
: 複製文件的同時複製權限信息,等同於執行了以下命令:
shutil.copy2(src,des)
: 比copy對了所有原數據,但須要平臺支持,等同於執行了以下命令:
shutil.copytree(src,dest,symlinks=False,ignore=None,copy_function=copy2,ignore_dangling_symlinks=False)
: 遞歸複製文件,相似於copy -r,默認使用copy2
ignore = func
, 提供一個callable(src,namnes) --> ignoted_names。提供一個函數,它會被調用。src是原目錄,names是原目錄下的文件列表(os.listdir(src)),返回值是要被過濾的文件名的set類型數據In [146]: def func(src,names): ...: ig = filter(lambda x: not x.endswith('conf'),names) ...: return set(ig) In [164]: os.listdir('old') Out[164]: ['123.txt', '456.txt', 'asound.conf', 'brltty.conf', 'chrony.conf', 'dleyna-server-service.conf', 'dnsmasq.conf', 'dracut.conf', 'e2fsck.conf', 'fprintd.conf', 'fuse.conf', 'GeoIP.conf', 'host.conf'] In [161]: shutil.copytree('old','new',ignore=func) Out[161]: 'new' In [163]: os.listdir('new') Out[163]: ['123.txt', '456.txt']
shutil模塊本身也實現了一個過濾某些特徵的方法,
shutil.ignore_patterns('*py')
,表示過濾*py的文件。
shutil.rmtree(path, ignore_errors=False, onerror=None)
: 遞歸的刪除文件,相似於rm -rf,須要注意的是它不是原子操做,若是刪除錯誤,就會中斷,已經刪除的就刪除了。
>>> os.system('ls -l') total 8 drwxr-xr-x 2 root root 4096 Mar 9 18:46 test drwxr-xr-x 2 root root 4096 Mar 9 18:46 test1 >>> shutil.rmtree('test1') >>> os.system('ls -l') total 4 drwxr-xr-x 2 root root 4096 Mar 9 18:46 test >>>
shutil.move(src,des,copy_function=copy2)
: 遞歸移動文件、目錄到目標、返回目標,相似於mv 命令,自己使用的是os.rename方法,若是不支持rename,若是是目錄則copytree再刪除原目錄。In [3]: import shutil In [4]: ls new/ old/ In [5]: shutil.move('new','/tmp/new') Out[5]: '/tmp/new' In [6]: ls old/ In [7]: shutil.move('old','new_old') Out[7]: 'new_old'
shutil.make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, owner=None, group=None, )
: 打包壓縮,支持"zip", "tar", "gztar","bztar", or "xztar"
In [14]: shutil.make_archive('abc','gztar',root_dir='new_old') Out[14]: '/home/python/py368/abc.tar.gz' In [15]: ls 123/ abc.tar.gz new_old/