Python shutil模塊常用函數詳解

Python shutil模塊常用函數詳解


shutil模塊提供了一些針對文件和目錄的高級操作,主要是拷貝、移動。對於單個文件的操作,還可參考os模塊

**Warning:**即使是高級別的拷貝函數(shutil.copy(),shutil.copy2())也不能拷貝所有的文件元數據。意思是:在POSIX系統中,文件所有者、屬組以及ACL信息會丟失。在Windows平臺上,文件所有者,ACL以及ADS(供選數據流)不會被複制。On Mac OS, the resource fork and other metadata are not used. This means that resources will be lost and file type and creator codes will not be correct.

目錄及文件操作

copyfileobj(fsrc, fdst[, length])

複製file-like對象fsrc的內容到fdst,如果fdst不存在則自動創建。length表示緩衝大小,如果是負數表示直接複製,不循環遍歷塊中的源數據。數據默認按塊讀取(16 * 1024)避免不可控的內存消耗。

import shutil

shutil.copyfileobj(open("fsrc.txt", "rb"), open("fdst.txt", "wb"))

copyfile(src, dst, *, follow_symlinks=True)

複製文件src的內容到dst並返回dst,如果dst不存在則自動創建。src和dst是字符串類型的路徑名,如果src和dst指向同一個文件,拋出SameFileError異常。

目標位置必須是可寫的,否則將拋出OSError異常(實際拋出的是PermissionError)。如果dst已經存在,則直接覆蓋。特殊文件比如塊設備、字符設備、管道不能使用此函數複製。

如果follow_symlinks爲False且src是軟鏈接,將創建一個新的軟鏈接替代拷貝行爲

shutil.copyfile("src.txt", "dst.txt")

copymode(src, dst, *, follow_symlinks=True)

複製文件src的權限位(permission bits)到dst,src和dst是字符串類型的路徑名。如果follow_symlinks爲False且src和dst都是軟鏈接,將修改dst軟鏈接文件而非源文件的權限。

此函數並非所有平臺可用,如果它不能修改本地平臺的軟鏈接但又執行了相關操作,將不做任何操作直接返回None

# 修改前
-rw-r--r--. 1 root  root    96 10月 11 12:26 aa.txt
-rw-------. 1 root  root  1362 9月   6 22:07 anaconda-ks.cfg
-rw-------. 1 admin admin    0 10月 11 12:53 bb.txt
lrwxrwxrwx. 1 root  root    21 10月 11 12:58 cc.txt -> /root/anaconda-ks.cfg

>>> shutil.copymode("aa.txt", "bb.txt")
>>> shutil.copymode("aa.txt", "cc.txt")

# 修改後
-rw-r--r--. 1 root  root    96 10月 11 12:26 aa.txt
-rw-r--r--. 1 root  root  1362 9月   6 22:07 anaconda-ks.cfg
-rw-r--r--. 1 admin admin    0 10月 11 12:53 bb.txt
lrwxrwxrwx. 1 root  root    21 10月 11 12:58 cc.txt -> /root/anaconda-ks.cfg

copystat(src, dst, *, follow_symlinks=True)

複製src的權限位、最後訪問時間、最後修改時間以及標誌(flag)到dst,src和dst是字符串類型的路徑名,可以是文件或目錄。在Linux平臺上還會複製擴展屬性。

如果follow_symlinks爲False,且src和dst都是軟鏈接,此函數直接操作軟鏈接而非源文件(目錄)。

**Note:**並非所有平臺都能檢查和修改軟鏈接,python能告訴用戶本地平臺可使用哪些功能。

  • 如果os.chmod in os.supports_follow_symlinks爲True,copystat()可以修改軟鏈接的權限位
  • 如果os.utime in os.supports_follow_symlinks爲True,copystat()可以修改軟鏈接的最後訪問時間和最後修改時間
  • 如果os.chflags in os.supports_follow_symlinks爲True,copystat()可以修改軟鏈接的flag

copystat()總是能成功執行,即使是在某些它的部分或全部功能不可用的平臺上修改軟鏈接,它將最大限度地拷貝它能拷貝的所有信息。

copy(src, dst, *, follow_symlinks=True)

複製文件src的內容和權限位到dst,dst可以是文件或目錄,如果是文件,函數的返回值就是dst,如果是目錄,函數的返回值就是src的文件名與dst的路徑拼接。src和dst都是字符串類型,如果dst指向一個目錄,則創建與src同名(basename)的新文件。

如果follow_symlinks爲False,且src是軟鏈接,dst將作爲軟鏈接創建;如果follow_symlinks爲True,src爲軟鏈接,則實際拷貝的是src指向的源文件。

copy()使用copymode()拷貝權限位,使用copyfile()拷貝文件內容

>>> shutil.copy("src.txt", "dst.txt")
'dst.txt'
>>> shutil.copy("src.txt", "/tmp/")
'/tmp/src.txt'
>>> shutil.copy("src.txt", "/Dota2/")     # 傳入一個不存在的目錄
Traceback (most recent call last):
  ...
IsADirectoryError: [Errno 21] Is a directory: '/Dota2/'

copy2(src, dst, *, follow_symlinks=True)

除了還會保留src的所有元數據(如創建時間、修改時間等),其他與copy()相同。

當follow_symlinks爲False且src爲軟鏈接時,dst將作爲軟鏈接被創建並拷貝src的所有元數據到dst。

copy2()使用copystat()拷貝元數據,使用copyfile()拷貝文件內容

ignore_patterns(*patterns)

創建並返回一個函數,可傳遞到copytree()中作爲ignore參數的值,忽略滿足匹配模式的文件和目錄

copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, ignore_dangling_symlinks=False)

遞歸複製以src爲根目錄的整個目錄樹,返回目標目錄dst。dst必須是不存在的目錄,它和它不存在的父目錄都將被創建。使用copystat()複製目錄元數據,使用copy2()複製文件內容和元數據

  • symlinks:如果值爲True,拷貝src目錄樹中的軟鏈接和軟鏈接的元數據到dst目錄樹;如果值爲False,拷貝src目錄樹中軟鏈接指向的源文件(目錄)的內容和元數據到dst目錄樹(需要注意的是,拷貝後的文件或目錄的名稱使用的是軟鏈接的名稱而非源文件或目錄的名稱),倘若源文件不存在將導致異常,異常信息保存在最終拋出的Error異常中。
  • ignore_dangling_symlinks:如果值爲True,可以忽略symlinks參數爲False時由於源文件不存在產生的異常。對於不支持os.symlink()的平臺,此參數無任何影響
  • ignore:必須是一個可調用對象,接收src目錄樹下的目錄和使用os.listdir()返回的該目錄下的文件、目錄列表。由於copytree()是遞歸調用的,因此src目錄樹下每個被複制的目錄都會調用一次ignore。
  • copy_function:必須是一個可調用對象,用於複製文件

原始目錄結構:

[root@localhost Shutil]# pwd
/root/Shutil
[root@localhost Shutil]# ll -R
.:
總用量 0
drwxr-xr-x. 3 root root 70 10月 12 10:48 src
drwxr-xr-x. 3 root root 33 10月 12 10:47 symlink

./src:
總用量 0
-rw-r--r--. 1 root root  0 10月 12 10:39 aa.txt
drwxr-xr-x. 2 root root  6 10月 12 10:40 dddir
lrwxrwxrwx. 1 root root 27 10月 12 10:48 ssdir_link -> /root/Shutil/symlink/ssdir/
lrwxrwxrwx. 1 root root 27 10月 12 10:48 ss_link.txt -> /root/Shutil/symlink/ss.txt

./src/dddir:
總用量 0

./symlink:
總用量 0
drwxr-xr-x. 2 root root 6 10月 12 10:57 ssdir
-rw-r--r--. 1 root root 0 10月 12 10:46 ss.txt

./symlink/ssdir:
總用量 0

shutil.copytree("/root/Shutil/src/", "/root/Shutil/dst/", symlinks=False)的執行結果:

[root@localhost Shutil]# ll dst/
總用量 0
-rw-r--r--. 1 root root 0 10月 12 10:39 aa.txt
drwxr-xr-x. 2 root root 6 10月 12 10:40 dddir
drwxr-xr-x. 2 root root 6 10月 12 10:57 ssdir_link
-rw-r--r--. 1 root root 0 10月 12 10:46 ss_link.txt

shutil.copytree("/root/Shutil/src/", "/root/Shutil/dst/", symlinks=True)的執行結果:

[root@localhost Shutil]# ll dst/
總用量 0
-rw-r--r--. 1 root root  0 10月 12 10:39 aa.txt
drwxr-xr-x. 2 root root  6 10月 12 10:40 dddir
lrwxrwxrwx. 1 root root 27 10月 12 10:48 ssdir_link -> /root/Shutil/symlink/ssdir/
lrwxrwxrwx. 1 root root 27 10月 12 10:48 ss_link.txt -> /root/Shutil/symlink/ss.txt

rmtree(path, ignore_errors=False, οnerrοr=None)

刪除目錄。path必須指代一個目錄(但不能是目錄的軟鏈接)。

  • ignore_errors:如果爲True,忽略目錄刪除失敗導致的異常,否則該異常將由onerror參數指定的函數處理。如果onerror爲None,該異常被拋出
  • onerror:必須是一個接收三個參數(function, path, excinfo)的可調用對象。

**Note:**在支持基於文件描述符的目錄訪問函數的平臺上,默認使用抗軟鏈接攻擊(symlink attack resistant)的rmtree()版本;其他平臺上的rmtree()的實現易遭受軟鏈接攻擊。可以用rmtree.avoids_symlink_attacks查看當前平臺的rmtree()方法能否抵抗軟鏈接攻擊

move(src, dst, copy_function=copy2)

移動文件或目錄到目標位置。

  • 如果目標位置dst是一個存在的[軟鏈接]目錄,將src(文件或目錄)移動到dst路徑下
# before
[root@localhost shutil_move]# pwd
/root/shutil_move
[root@localhost shutil_move]# ll
總用量 0
drwxr-xr-x. 2 root root  6 10月 12 14:41 dst_dir
drwxr-xr-x. 2 root root 20 10月 12 14:39 src

>>> shutil.move("/root/shutil_move/src/", "/root/shutil_move/dst_dir/")
'/root/shutil_move/dst_dir/src'

# after
[root@localhost shutil_move]# ll -R
.:
總用量 0
drwxr-xr-x. 3 root root 17 10月 12 14:43 dst_dir

./dst_dir:
總用量 0
drwxr-xr-x. 2 root root 6 10月 12 14:45 src

./dst_dir/src:
總用量 0
  • 如果目標位置dst是一個不存在的目錄,創建dst及其不存在的父級目錄,將src(文件)移動到dst路徑下或將src(目錄)移動並重命名爲dst
# before
[root@localhost shutil_move]# pwd
/root/shutil_move
[root@localhost shutil_move]# ll
總用量 0
drwxr-xr-x. 2 root root 6 10月 12 14:55 src
[root@localhost shutil_move]# ll /tmp/
總用量 0

>>> shutil.move("/root/shutil_move/src/", "/tmp/a/b/dst/")
'/tmp/a/b/dst/'

# after
[root@localhost shutil_move]# ll
總用量 0
[root@localhost shutil_move]# ll -R /tmp/
/tmp/:
總用量 0
drwxr-xr-x. 3 root root 15 10月 12 14:57 a

/tmp/a:
總用量 0
drwxr-xr-x. 3 root root 17 10月 12 14:57 b

/tmp/a/b:
總用量 0
drwxr-xr-x. 2 root root 6 10月 12 14:55 dst

/tmp/a/b/dst:
總用量 0
  • 如果dst非目錄,且dst存在或其上級目錄存在
    • src是普通文件,dst是普通文件或軟鏈接文件,移動src並重命名爲dst。原始dst如果存在則被直接覆蓋
    • src是軟鏈接文件,dst是普通文件或軟鏈接文件,移動src並重命名爲dst,指向的真實文件爲src之前指向的源文件。原始dst如果存在則被直接覆蓋

disk_usage(path)

以命名元組的方式(total, used, free)返回指定path的磁盤使用數據,單位爲byte。在Windows平臺,path必須指代目錄;在Unix平臺path可以是目錄或文件

chown(path, user=None, group=None)

改變指定path的所有者和屬組。

user和group參數,可以是系統上的用戶名/組名或uid/gid。至少需要傳遞其中一個參數

which(cmd, mode=os.F_OK | os.X_OK, path=None)

返回cmd調用的可執行文件路徑,沒有返回None。

  • mode:傳遞給os.access()的權限掩碼(permission mask),默認值爲os.F_OK | os.X_OK,用於判斷文件是否存在或可執行。
  • path:cmd的查找路徑。如果未指定,在os.environ的"PATH"key指代的路徑查找,如果"PATH"不存在,使用os.defpath作爲默認路徑。

在Windows平臺,不管使用默認path還是自定義的path,查找路徑都將包含當前工作目錄且處於最高優先級。此外,在查找cmd時,還會檢查環境變量PATHEXT

>>> shutil.which("python3")
'D:\\Program Files\\Python36\\python3.EXE'

copytree示例

使用ignore_patterns()忽略拷貝後綴爲.pyc的文件和tmp打頭的文件或文件夾:

from shutil import copytree, ignore_patterns

copytree(source, destination, ignore=ignore_patterns('*.pyc', 'tmp*'))

使用ignore參數記錄日誌:

from shutil import copytree
import logging

def _logpath(path, names):
    logging.info('Working in %s', path)
    return []   # nothing will be ignored

copytree(source, destination, ignore=_logpath)

rmtree示例

import os, stat
import shutil

def remove_readonly(func, path, _):
    "Clear the readonly bit and reattempt the removal"
    os.chmod(path, stat.S_IWRITE)
    func(path)

shutil.rmtree(directory, onerror=remove_readonly)

歸檔操作

基於zipfile和tarfile模塊提供創建和讀取歸檔文件的功能。

make_archive(base_name, format[, root_dir[, base_dir[, verbose[, dry_run[, owner[, group[, logger]]]]]]])

創建歸檔文件,並返回歸檔文件的名稱。

  • base_name:要創建的歸檔文件的名稱(不包含擴展名),可以包含路徑表示歸檔文件的目標位置
  • format:歸檔文件的格式(zip, tar, gztar, bztar, xztar)
  • root_dir:歸檔文件的根目錄(默認當前目錄)
  • base_dir:歸檔文件中所有文件和目錄的前綴路徑(默認當前目錄)
  • dry_run:如果爲True,不創建歸檔文件,但是將執行的操作記錄在logger中
  • owner/group:歸檔文件中所有文件和目錄的所屬用戶和組。如果format爲"zip",owner和group的配置不生效
  • logger:通常使用logging.Logger對象
  • verbose:已棄用
# /root/demo/ 歸檔該目錄下的文件和文件夾
# /tmp/shutil/ 生成的歸檔文件中的所有內容的前綴路徑
>>> shutil.make_archive("/root/demo_zip/zipfile", "zip", "/root/demo/", "/tmp/shutil/")
'/root/demo_zip/zipfile.zip'
[root@localhost demo_zip]# unzip -l zipfile.zip 
Archive:  zipfile.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  10-15-2018 11:03   tmp/shutil/
        0  10-15-2018 11:03   tmp/shutil/aa.txt
        0  10-15-2018 11:03   tmp/shutil/bb.txt
        0  10-15-2018 11:03   tmp/shutil/cc.txt
---------                     -------
        0                     4 files

get_archive_formats()

返回支持的歸檔格式列表,列表中的每個元素是(name, description)形式的元組。
默認支持的格式如下:

  • zip:需要zlib模塊支持
  • tar
  • gztar:需要zlib模塊支持
  • bztar:需要bz2模塊支持
  • xztar:需要lzma模塊支持

用戶可以通過register_archive_format()註冊新的格式或者自定義已存在格式的歸檔行爲

register_archive_format(name, function[, extra_args[, description]])

註冊格式爲name的歸檔器

unregister_archive_format(name)

從支持的歸檔格式中移除name

unpack_archive(filename[, extract_dir[, format]])

解壓歸檔文件。

  • filename:歸檔文件名稱
  • extract_dir:歸檔文件解壓的目標位置。默認使用當前目錄
  • format:使用指定格式的解壓器解壓歸檔文件,默認使用filename參數的擴展名。如果不存在對應的解壓器,拋出ValueError異常

register_unpack_format(name, extensions, function[, extra_args[, description]])

註冊格式爲name的解壓器

unregister_unpack_format(name)

從支持的解壓格式中移除name

get_unpack_formats()

返回支持的解壓格式列表,列表中的每個元素是(name, extensions, description)形式的元組。

查詢終端大小

get_terminal_size(fallback=(columns, lines))

獲取終端窗口的大小。

如果環境變量中定義了正整數的COLUMNSLINES,返回該大小。

如果COLUMNSLINES未定義(多數情況都是如此),返回調用os.get_terminal_size()查詢連接到sys.__stdout__的終端的大小。

如果終端大小不能被查詢(系統不支持或者未連接到終端),使用fallback參數提供的大小作爲後備值,默認是(80, 24)

轉載於:python模塊之shutil

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