python工具庫介紹-pathlib: 檔案系統物件
目的:使用面向物件的API解析,構建,測試和處理檔名和路徑,而不是底層的字串操作。
Path表示
pathlib包含用於管理使用POSIX標準或Microsoft Windows語法格式化的檔案系統路徑的類。它包括所謂的“pure”類,它們對字串進行操作,但不與實際的檔案系統進行互動;“concrete”類將API擴充套件為包含反映或修改本地檔案系統資料的操作。
pure類PurePosixPath和PureWindowsPath可以在任何作業系統上例項化和使用,因為它們只用於名稱。要例項化正確的類來處理真實的檔案系統,請使用Path來獲取PosixPath或WindowsPath,具體取決於平臺。
構建Path
要例項化路徑,字串作為引數。Path物件的字串表示是該字串。要建立引用相對於現有路徑的值的新路徑,請使用/運算子來擴充套件路徑。運算子的引數可以是字串或其他路徑物件。
import pathlib usr = pathlib.PurePosixPath('/usr') print(usr) usr_local = usr / 'local' print(usr_local) usr_share = usr / pathlib.PurePosixPath('share') print(usr_share) root = usr / '..' print(root) etc = root / '/etc/' print(etc)
執行結果
/usr /usr/local /usr/share /usr/.. /etc
正如示例輸出中的root值所示,操作符按照給定的方式組合路徑值,並且在包含父目錄引用“..”的情況下不會對結果進行解析。 但是,如果以os.sep開頭它被解釋為新的“根”引用。
具體路徑類的resolve()方法,通過檢視目錄和符號連結的檔案系統來解析路徑,並生成名稱引用的絕對路徑。
# pathlib_resolve.py import pathlib usr_local = pathlib.Path('/usr/local') share = usr_local / '..' / 'share' print(type(share.resolve())) print(share.resolve())
執行結果:
<class 'pathlib.PosixPath'> /usr/share
joinpath()可以組合路徑。
# pathlib_joinpath.py import pathlib root = pathlib.PurePosixPath('/') subdirs = ['usr', 'local'] usr_local = root.joinpath(*subdirs) print(usr_local)
執行結果:
$ python3 pathlib_joinpath.py /usr/local
使用with_name()建立新路徑,用不同的檔名替換路徑的名稱部分。 使用Use with_suffix()建立新路徑,用不同的值替換檔名的副檔名。
# pathlib_from_existing.py import pathlib ind = pathlib.PurePosixPath('source/pathlib/index.rst') print(ind) py = ind.with_name('pathlib_from_existing.py') print(py) pyc = py.with_suffix('.pyc') print(pyc)
執行結果:
$ python3 pathlib_from_existing.py source/pathlib/index.rst source/pathlib/pathlib_from_existing.py source/pathlib/pathlib_from_existing.pyc
解析路徑
Path物件具有用於從名稱中提取部分值的方法和屬性。例如,parts屬性會生成一系列基於路徑分隔符值解析的路徑段。
# pathlib_parts.py import pathlib p = pathlib.PurePosixPath('/usr/local') print(p.parts)
執行結果:
$ python3 pathlib_parts.py ('/', 'usr', 'local')
有兩種方法可以從給定的路徑物件中“向上”導航檔案系統層次結構。父屬性引用包含路徑的目錄的新路徑例項,即os.path.dirname()返回的值。父項屬性是迭代器,它產生父目錄引用,不斷地向上“提升”路徑層次直到到達根目錄。
import pathlib p = pathlib.PurePosixPath('/usr/local/lib') print('parent: {}'.format(p.parent)) print('\nhierarchy:') for up in p.parents: print(up)
執行結果:
$ python3 pathlib_parents.py parent: /usr/local hierarchy: /usr/local /usr /
路徑的其他部分可以通過路徑物件的屬性來訪問。 name屬性儲存最後一個路徑分隔符(與 os.path.basename()產生的值相同)後的最後一部分路徑。字尾屬性儲存擴充套件分隔符後面的值,並且stem屬性保留後綴之前的名稱部分。
# pathlib_name.py import pathlib p = pathlib.PurePosixPath('./source/pathlib/pathlib_name.py') print('path: {}'.format(p)) print('name: {}'.format(p.name)) print('suffix: {}'.format(p.suffix)) print('stem: {}'.format(p.stem))
執行結果:
$ python3 pathlib_name.py path: source/pathlib/pathlib_name.py name: pathlib_name.py suffix: .py stem: pathlib_name
儘管suffix和stem與 os.path.splitext()生成的值相似,但值僅基於name而不是完整路徑。
建立Concrete路徑
Concrete Path類的例項可以通過引用檔案系統上的檔案,目錄或符號連結的名稱(或潛在名稱)的字串引數來建立。 該類還提供了幾種便捷方法來構建使用常用位置(如當前工作目錄和使用者主目錄)的例項。
# pathlib_convenience.py import pathlib home = pathlib.Path.home() print('home: ', home) cwd = pathlib.Path.cwd() print('cwd : ', cwd)
執行結果:
home:/home/andrew cwd :/home/andrew/code/python-chinese-library/libraries/pathlib stem: pathlib_name
目錄內容
有三種方法可以訪問目錄列表,以發現檔案系統上可用檔案的名稱。 iterdir()是生成器,為包含目錄中的每個專案生成新的Path例項。
# pathlib_convenience.py import pathlib home = pathlib.Path.home() print('home: ', home) cwd = pathlib.Path.cwd() print('cwd : ', cwd)
執行結果:
pathlib_name.py pathlib_parents.py pathlib_parts.py pathlib_joinpath.py pathlib_from_existing.py pathlib_operator.py pathlib_resolve.py pathlib_convenience.py pathlib_iterdir.py
如果路徑不是目錄,則iterdir()會引發NotADirectoryError。
使用glob()僅查詢匹配模式的檔案。
import pathlib p = pathlib.Path('.') for f in p.glob('*.py'): print(f)
執行結果:
pathlib_glob.py pathlib_name.py pathlib_parents.py pathlib_parts.py pathlib_glob.py pathlib_joinpath.py pathlib_from_existing.py pathlib_operator.py pathlib_resolve.py pathlib_convenience.py pathlib_iterdir.py
glob處理器支援使用模式字首**或通過呼叫rglob()而不是glob()來進行遞迴掃描。
# pathlib_rglob.py import pathlib p = pathlib.Path('..') for f in p.rglob('*.py'): print(f)
執行結果:
../heapq/heapq_demo.py ../_dubbo/dubbo.py ../pathlib/pathlib_name.py ../pathlib/pathlib_parents.py ../pathlib/pathlib_rglob.py ../pathlib/pathlib_parts.py ...
下面的兩種用法也實現了類似的功能:
# pathlib_rglob2.py import pathlib p = pathlib.Path('..') for f in p.rglob('**/*.py'): print(f)
# pathlib_rglob3.py import pathlib p = pathlib.Path('..') for f in p.glob('**/*.py'): print(f)
上面在指定目錄中查詢特定型別的檔案,或許是pathlib中最有用的功能了。
讀寫檔案
每個Path例項都包含處理它所引用的檔案內容的方法。 要立即檢索內容,請使用read_bytes()或read_text()。 要寫入檔案,請使用write_bytes()或write_text()。 使用open()方法開啟檔案並保留檔案控制代碼,而不是將名稱傳遞給內建的open()函式。
# pathlib_read_write.py import pathlib f = pathlib.Path('example.txt') f.write_bytes('This is the content'.encode('utf-8')) with f.open('r', encoding='utf-8') as handle: print('read from open(): {!r}'.format(handle.read())) print('read_text(): {!r}'.format(f.read_text('utf-8')))
執行結果:
read from open(): 'This is the content' read_text(): 'This is the content'
目錄和符號連結
不存在的目錄或符號連結的路徑可用於建立。
如果路徑已經存在,mkdir()會引發一個FileExistsError。
# pathlib_mkdir.py import pathlib p = pathlib.Path('example_dir') print('Creating {}'.format(p)) p.mkdir()
執行結果:
$ python3 pathlib_mkdir.py Creating example_dir $ python3 pathlib_mkdir.py Creating example_dir Traceback (most recent call last): File "pathlib_mkdir.py", line 16, in <module> p.mkdir() File ".../lib/python3.5/pathlib.py", line 1214, in mkdir self._accessor.mkdir(self, mode) File ".../lib/python3.5/pathlib.py", line 371, in wrapped return strfunc(str(pathobj), *args) FileExistsError: [Errno 17] File exists: 'example_dir'
使用symlink_to() 建立符號連結。該連結將根據路徑的值進行命名,並將引用作為symlink_to()的引數的名稱。
# pathlib_symlink_to.py import pathlib p = pathlib.Path('example_link') p.symlink_to('example.txt') print(p) print(p.resolve().name)
執行結果:
example_link example.txt
檔案型別
Path例項包含幾種用於測試路徑引用的檔案型別的方法。本示例建立了多個不同型別的檔案,並測試這些檔案以及本地作業系統上可用的一些其他裝置特定的檔案。
# pathlib_types.py import itertools import os import pathlib root = pathlib.Path('test_files') # Clean up from previous runs. if root.exists(): for f in root.iterdir(): f.unlink() else: root.mkdir() # Create test files (root / 'file').write_text( 'This is a regular file', encoding='utf-8') (root / 'symlink').symlink_to('file') os.mkfifo(str(root / 'fifo')) # Check the file types to_scan = itertools.chain( root.iterdir(), [pathlib.Path('/dev/disk0'), pathlib.Path('/dev/console')], ) hfmt = '{:18s}' + ('{:>5}' * 6) print(hfmt.format('Name', 'File', 'Dir', 'Link', 'FIFO', 'Block', 'Character')) print() fmt = '{:20s}' + ('{!r:>5}' * 6) for f in to_scan: print(fmt.format( str(f), f.is_file(), f.is_dir(), f.is_symlink(), f.is_fifo(), f.is_block_device(), f.is_char_device(), ))
is_dir(), is_file(), is_symlink(), is_socket(), is_fifo(), is_block_device(), is_char_device()都不帶任何引數。
執行結果:
NameFileDirLinkFIFOBlockCharacter test_files/fileTrueFalseFalseFalseFalseFalse test_files/fifoFalseFalseFalseTrueFalseFalse test_files/symlinkTrueFalseTrueFalseFalseFalse /dev/disk0FalseFalseFalseFalseFalseFalse /dev/consoleFalseFalseFalseFalseFalseTrue
這裡格式化的方法挺有意思。
檔案屬性
有關檔案的詳細資訊可以使用stat() 或lstat() 方法來訪問(用於檢查可能是符號連結的狀態)。這些方法產生與os.stat() os.lstat() 相同的結果。
import pathlib import sys import time if len(sys.argv) == 1: filename = __file__ else: filename = sys.argv[1] p = pathlib.Path(filename) stat_info = p.stat() print('{}:'.format(filename)) print('Size:', stat_info.st_size) print('Permissions:', oct(stat_info.st_mode)) print('Owner:', stat_info.st_uid) print('Device:', stat_info.st_dev) print('Created:', time.ctime(stat_info.st_ctime)) print('Last modified:', time.ctime(stat_info.st_mtime)) print('Last accessed:', time.ctime(stat_info.st_atime))
執行結果:
$ python3 pathlib_stat.py pathlib_stat.py: Size: 607 Permissions: 0o100644 Owner: 527 Device: 16777218 Created: Thu Dec 29 12:25:25 2016 Last modified: Thu Dec 29 12:25:25 2016 Last accessed: Thu Dec 29 12:25:34 2016 $ python3 pathlib_stat.py index.rst index.rst: Size: 19363 Permissions: 0o100644 Owner: 527 Device: 16777218 Created: Thu Dec 29 11:27:58 2016 Last modified: Thu Dec 29 11:27:58 2016 Last accessed: Thu Dec 29 12:25:33 2016FalseFalseFalseFalseFalseTrue
要更簡單地訪問有關檔案所有者的資訊,請使用owner()和group()。
# pathlib_ownership.py import pathlib p = pathlib.Path(__file__) print('{} is owned by {}/{}'.format(p, p.owner(), p.group()))
執行結果:
/home/andrew/code/python-chinese-library/libraries/pathlib/pathlib_ownership.py is owned by andrew/andrew
stat() 返回數字,這些方法將查詢與ID相關聯的名稱。
touch()方法與Unix命令touch類似,用於建立檔案或更新現有檔案的修改時間和許可權。
# pathlib_touch.py import pathlib import time p = pathlib.Path('touched') if p.exists(): print('already exists') else: print('creating new') p.touch() start = p.stat() time.sleep(1) p.touch() end = p.stat() print('Start:', time.ctime(start.st_mtime)) print('End:', time.ctime(end.st_mtime))
執行結果:
$ python3 pathlib_touch.py creating new Start: Thu Dec 29 12:25:34 2016 End: Thu Dec 29 12:25:35 2016 $ python3 pathlib_touch.py already exists Start: Thu Dec 29 12:25:35 2016 End: Thu Dec 29 12:25:36 2016
許可權
在類Unix系統上,可以使用chmod()更改檔案許可權,將模式作為整數傳遞。模式值可以使用stat模組中定義的常量來構造。這個例子切換使用者的執行許可權位。
指令碼假定它具有執行時修改檔案模式所需的許可權。
# pathlib_chmod.py import os import pathlib import stat # Create a fresh test file. f = pathlib.Path('pathlib_chmod_example.txt') if f.exists(): f.unlink() f.write_text('contents') # Determine what permissions are already set using stat. existing_permissions = stat.S_IMODE(f.stat().st_mode) print('Before: {:o}'.format(existing_permissions)) # Decide which way to toggle them. if not (existing_permissions & os.X_OK): print('Adding execute permission') new_permissions = existing_permissions | stat.S_IXUSR else: print('Removing execute permission') # use xor to remove the user execute permission new_permissions = existing_permissions ^ stat.S_IXUSR # Make the change and show the new value. f.chmod(new_permissions) after_permissions = stat.S_IMODE(f.stat().st_mode) print('After: {:o}'.format(after_permissions))
執行結果:
$ python3 pathlib_chmod.py Before: 644 Adding execute permission After: 744
刪除
有兩種從檔案系統中刪除東西的方法,具體取決於型別。要刪除空目錄,請使用rmdir()。
# pathlib_rmdir.py import pathlib p = pathlib.Path('example_dir') print('Removing {}'.format(p)) p.rmdir()
執行結果:
$ python3 pathlib_rmdir.py Removing example_dir $ python3 pathlib_rmdir.py Removing example_dir Traceback (most recent call last): File "pathlib_rmdir.py", line 16, in <module> p.rmdir() File ".../lib/python3.5/pathlib.py", line 1262, in rmdir self._accessor.rmdir(self) File ".../lib/python3.5/pathlib.py", line 371, in wrapped return strfunc(str(pathobj), *args) FileNotFoundError: [Errno 2] No such file or directory: 'example_dir'
如果目錄不存在,則會引發FileNotFoundError異常。嘗試刪除非空的目錄也是錯誤的。
對於檔案,符號連結和大多數其他路徑型別使用unlink()。
使用者必須具有刪除檔案,符號連結,套接字或其他檔案系統物件的許可權。
# pathlib_unlink.py import pathlib p = pathlib.Path('touched') p.touch() print('exists before removing:', p.exists()) p.unlink() print('exists after removing:', p.exists())
執行結果:
$ python3 pathlib_unlink.py exists before removing: True exists after removing: False
參考資料
- ofollow,noindex">本文相關書籍下載
- 本文涉及的python測試開發庫 謝謝點贊!
- 討論qq群144081101 591302926 567351477 釘釘免費群21745728
- https://docs.python.org/3/library/pathlib.html
- https://pymotw.com/3/pathlib/index.html
- 程式碼地址