python shutil模塊批量操作文件(移動 復制 打包 壓縮 解壓)

python之模塊之shutil模塊

參考:

python之模塊之shutil模塊

https://www.cnblogs.com/MnCu8261/p/5494807.html#undefined

python學習筆記-Day7(configparser模塊、shutil、壓縮與解壓模塊、subprocess)

http://www.mamicode.com/info-detail-1408907.html

shutil

-- --High-level file operations? 高級的文件操作模塊。

os模塊提供了對目錄或者文件的新建/刪除/查看文件屬性,還提供了對文件以及目錄的路徑操作。比如說:絕對路徑,父目錄……? 但是,os文件的操作還應該包含移動 復制? 打包 壓縮 解壓等操作,這些os模塊都沒有提供。

而本章所講的shutil則就是對os中文件操作的補充。--移動 復制? 打包 壓縮 解壓,

shutil功能:

1? shutil.copyfileobj(fsrc, fdst[, length=16*1024])? ? #copy文件內容到另一個文件,可以copy指定大小的內容

#先來看看其源代碼。defcopyfileobj(fsrc, fdst, length=16*1024):"""copy data from file-like object fsrc to file-like object fdst"""while1:

buf=fsrc.read(length)ifnotbuf:breakfdst.write(buf)#注意! 在其中fsrc,fdst都是文件對象,都需要打開后才能進行復制操作importshutil

f1=open('name','r')

f2=open('name_copy','w+')

shutil.copyfileobj(f1,f2,length=16*1024)

2? shutil.copyfile(src,dst)?? #copy文件內容,是不是感覺上面的文件復制很麻煩?還需要自己手動用open函數打開文件,在這里就不需要了,事實上,copyfile調用了copyfileobj

defcopyfile(src, dst, *, follow_symlinks=True):"""Copy data from src to dst.

If follow_symlinks is not set and src is a symbolic link, a new

symlink will be created instead of copying the file it points to."""if_samefile(src, dst):raiseSameFileError("{!r} and {!r} are the same file".format(src, dst))forfnin[src, dst]:try:

st=os.stat(fn)exceptOSError:#File most likely does not existpasselse:#XXX What about other special files? (sockets, devices...)ifstat.S_ISFIFO(st.st_mode):raiseSpecialFileError("`%s` is a named pipe"%fn)ifnotfollow_symlinksandos.path.islink(src):

os.symlink(os.readlink(src), dst)else:

with open(src,'rb') as fsrc:

with open(dst,'wb') as fdst:

copyfileobj(fsrc, fdst)returndst

shutil.copyfile('name','name_copy_2')#一句就可以實現復制文件內容

3? shutil.copymode(src,dst)?? #僅copy權限,不更改文件內容,組和用戶。

defcopymode(src, dst, *, follow_symlinks=True):"""Copy mode bits from src to dst.

If follow_symlinks is not set, symlinks aren't followed if and only

if both `src` and `dst` are symlinks.? If `lchmod` isn't available

(e.g. Linux) this method does nothing."""ifnotfollow_symlinksandos.path.islink(src)andos.path.islink(dst):ifhasattr(os,'lchmod'):

stat_func, chmod_func=os.lstat, os.lchmodelse:returnelifhasattr(os,'chmod'):

stat_func, chmod_func=os.stat, os.chmodelse:returnst=stat_func(src)

chmod_func(dst, stat.S_IMODE(st.st_mode))

#先看兩個文件的權限[root@slyoyo python_test]#ls -ltotal 4-rw-r--r--. 1 root root 79 May 14 05:17test1-rwxr-xr-x. 1 root root? 0 May 14 19:10test2#運行命令>>>importshutil>>> shutil.copymode('test1','test2')#查看結果[root@slyoyo python_test]#ls -ltotal 4-rw-r--r--. 1 root root 79 May 14 05:17test1-rw-r--r--. 1 root root? 0 May 14 19:10test2#當我們將目標文件換為一個不存在的文件時報錯>>> shutil.copymode('test1','test3')

Traceback (most recent call last):

File"", line 1,inFile"/usr/local/python/lib/python3.4/shutil.py", line 132,incopymode

chmod_func(dst, stat.S_IMODE(st.st_mode))

FileNotFoundError: [Errno2] No such fileordirectory:'test233'

4? shutil.copystat(src,dst)??? #復制所有的狀態信息,包括權限,組,用戶,時間等

defcopystat(src, dst, *, follow_symlinks=True):"""Copy all stat info (mode bits, atime, mtime, flags) from src to dst.

If the optional flag `follow_symlinks` is not set, symlinks aren't followed if and

only if both `src` and `dst` are symlinks."""def_nop(*args, ns=None, follow_symlinks=None):pass#follow symlinks (aka don't not follow symlinks)follow = follow_symlinksornot(os.path.islink(src)andos.path.islink(dst))iffollow:#use the real function if it existsdeflookup(name):returngetattr(os, name, _nop)else:#use the real function only if it exists#*and* it supports follow_symlinksdeflookup(name):

fn=getattr(os, name, _nop)iffninos.supports_follow_symlinks:returnfnreturn_nop

st= lookup("stat")(src, follow_symlinks=follow)

mode=stat.S_IMODE(st.st_mode)

lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),

follow_symlinks=follow)try:

lookup("chmod")(dst, mode, follow_symlinks=follow)exceptNotImplementedError:#if we got a NotImplementedError, it's because#* follow_symlinks=False,#* lchown() is unavailable, and#* either#* fchownat() is unavailable or#* fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.#(it returned ENOSUP.)#therefore we're out of options--we simply cannot chown the#symlink.? give up, suppress the error.#(which is what shutil always did in this circumstance.)passifhasattr(st,'st_flags'):try:

lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)exceptOSError as why:forerrin'EOPNOTSUPP','ENOTSUP':ifhasattr(errno, err)andwhy.errno ==getattr(errno, err):breakelse:raise_copyxattr(src, dst, follow_symlinks=follow)

5? shutil.copy(src,dst)?? #復制文件的內容以及權限,先copyfile后copymode

defcopy(src, dst, *, follow_symlinks=True):"""Copy data and mode bits ("cp src dst"). Return the file's destination.

The destination may be a directory.

If follow_symlinks is false, symlinks won't be followed. This

resembles GNU's "cp -P src dst".

If source and destination are the same file, a SameFileError will be

raised."""ifos.path.isdir(dst):

dst=os.path.join(dst, os.path.basename(src))

copyfile(src, dst, follow_symlinks=follow_symlinks)

copymode(src, dst, follow_symlinks=follow_symlinks)returndst

6? shutil.copy2(src,dst)??? #復制文件的內容以及文件的所有狀態信息。先copyfile后copystat

defcopy2(src, dst, *, follow_symlinks=True):"""Copy data and all stat info ("cp -p src dst"). Return the file's

destination."

The destination may be a directory.

If follow_symlinks is false, symlinks won't be followed. This

resembles GNU's "cp -P src dst"."""ifos.path.isdir(dst):

dst=os.path.join(dst, os.path.basename(src))

copyfile(src, dst, follow_symlinks=follow_symlinks)

copystat(src, dst, follow_symlinks=follow_symlinks)returndst

7shutil.copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,ignore_dangling_symlinks=False) ? #遞歸的復制文件內容及狀態信息

defcopytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,

ignore_dangling_symlinks=False):"""Recursively copy a directory tree.

The destination directory must not already exist.

If exception(s) occur, an Error is raised with a list of reasons.

If the optional symlinks flag is true, symbolic links in the

source tree result in symbolic links in the destination tree; if

it is false, the contents of the files pointed to by symbolic

links are copied. If the file pointed by the symlink doesn't

exist, an exception will be added in the list of errors raised in

an Error exception at the end of the copy process.

You can set the optional ignore_dangling_symlinks flag to true if you

want to silence this exception. Notice that this has no effect on

platforms that don't support os.symlink.

The optional ignore argument is a callable. If given, it

is called with the `src` parameter, which is the directory

being visited by copytree(), and `names` which is the list of

`src` contents, as returned by os.listdir():

callable(src, names) -> ignored_names

Since copytree() is called recursively, the callable will be

called once for each directory that is copied. It returns a

list of names relative to the `src` directory that should

not be copied.

The optional copy_function argument is a callable that will be used

to copy each file. It will be called with the source path and the

destination path as arguments. By default, copy2() is used, but any

function that supports the same signature (like copy()) can be used."""names=os.listdir(src)ifignoreisnotNone:

ignored_names=ignore(src, names)else:

ignored_names=set()

os.makedirs(dst)

errors=[]fornameinnames:ifnameinignored_names:continuesrcname=os.path.join(src, name)

dstname=os.path.join(dst, name)try:ifos.path.islink(srcname):

linkto=os.readlink(srcname)ifsymlinks:#We can't just leave it to `copy_function` because legacy#code with a custom `copy_function` may rely on copytree#doing the right thing.os.symlink(linkto, dstname)

copystat(srcname, dstname, follow_symlinks=notsymlinks)else:#ignore dangling symlink if the flag is onifnotos.path.exists(linkto)andignore_dangling_symlinks:continue#otherwise let the copy occurs. copy2 will raise an errorifos.path.isdir(srcname):

copytree(srcname, dstname, symlinks, ignore,

copy_function)else:

copy_function(srcname, dstname)elifos.path.isdir(srcname):

copytree(srcname, dstname, symlinks, ignore, copy_function)else:#Will raise a SpecialFileError for unsupported file typescopy_function(srcname, dstname)#catch the Error from the recursive copytree so that we can#continue with other filesexceptError as err:

errors.extend(err.args[0])exceptOSError as why:

errors.append((srcname, dstname, str(why)))try:

copystat(src, dst)exceptOSError as why:#Copying file access times may fail on Windowsifgetattr(why,'winerror', None)isNone:

errors.append((src, dst, str(why)))iferrors:raiseError(errors)returndst#version vulnerable to race conditions

[root@slyoyo python_test]#tree copytree_test/copytree_test/└── test

├── test1

├── test2

└── hahaha

[root@slyoyo test]#ls -ltotal 0-rw-r--r--. 1 python python 0 May 14 19:36hahaha-rw-r--r--. 1 python python 0 May 14 19:36test1-rw-r--r--. 1 root? root? 0 May 14 19:36test2>>> shutil.copytree('copytree_test','copytree_copy')'copytree_copy'[root@slyoyo python_test]#ls -ltotal 12drwxr-xr-x. 3 root? root? 4096 May 14 19:36copytree_copy

drwxr-xr-x. 3 root? root? 4096 May 14 19:36copytree_test-rw-r--r--. 1 python python? 79 May 14 05:17test1-rw-r--r--. 1 root? root? ? ? 0 May 14 19:10test2

[root@slyoyo python_test]#tree copytree_copy/copytree_copy/└── test

├── hahaha

├── test1

└── test2

8? shutil.rmtree(path, ignore_errors=False, onerror=None)#遞歸地刪除文件

defrmtree(path, ignore_errors=False, onerror=None):"""Recursively delete a directory tree.

If ignore_errors is set, errors are ignored; otherwise, if onerror

is set, it is called to handle the error with arguments (func,

path, exc_info) where func is platform and implementation dependent;

path is the argument to that function that caused it to fail; and

exc_info is a tuple returned by sys.exc_info().? If ignore_errors

is false and onerror is None, an exception is raised."""ifignore_errors:defonerror(*args):passelifonerrorisNone:defonerror(*args):raiseif_use_fd_functions:#While the unsafe rmtree works fine on bytes, the fd based does not.ifisinstance(path, bytes):

path=os.fsdecode(path)#Note: To guard against symlink races, we use the standard#lstat()/open()/fstat() trick.try:

orig_st=os.lstat(path)exceptException:

onerror(os.lstat, path, sys.exc_info())returntry:

fd=os.open(path, os.O_RDONLY)exceptException:

onerror(os.lstat, path, sys.exc_info())returntry:ifos.path.samestat(orig_st, os.fstat(fd)):

_rmtree_safe_fd(fd, path, onerror)try:

os.rmdir(path)exceptOSError:

onerror(os.rmdir, path, sys.exc_info())else:try:#symlinks to directories are forbidden, see bug #1669raiseOSError("Cannot call rmtree on a symbolic link")exceptOSError:

onerror(os.path.islink, path, sys.exc_info())finally:

os.close(fd)else:return_rmtree_unsafe(path, onerror)#Allow introspection of whether or not the hardening against symlink#attacks is supported on the current platformrmtree.avoids_symlink_attacks = _use_fd_functions

9? shutil.move(src, dst) ?? #遞歸的移動文件

defmove(src, dst):"""Recursively move a file or directory to another location. This is

similar to the Unix "mv" command. Return the file or directory's

destination.

If the destination is a directory or a symlink to a directory, the source

is moved inside the directory. The destination path must not already

exist.

If the destination already exists but is not a directory, it may be

overwritten depending on os.rename() semantics.

If the destination is on our current filesystem, then rename() is used.

Otherwise, src is copied to the destination and then removed. Symlinks are

recreated under the new name if os.rename() fails because of cross

filesystem renames.

A lot more could be done here...? A look at a mv.c shows a lot of

the issues this implementation glosses over."""real_dst=dstifos.path.isdir(dst):if_samefile(src, dst):#We might be on a case insensitive filesystem,#perform the rename anyway.os.rename(src, dst)returnreal_dst=os.path.join(dst, _basename(src))ifos.path.exists(real_dst):raiseError("Destination path '%s' already exists"%real_dst)try:

os.rename(src, real_dst)exceptOSError:ifos.path.islink(src):

linkto=os.readlink(src)

os.symlink(linkto, real_dst)

os.unlink(src)elifos.path.isdir(src):if_destinsrc(src, dst):raiseError("Cannot move a directory '%s' into itself '%s'."%(src, dst))

copytree(src, real_dst, symlinks=True)

rmtree(src)else:

copy2(src, real_dst)

os.unlink(src)returnreal_dst

10? make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,dry_run=0, owner=None, group=None, logger=None)? #壓縮打包

defmake_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,

dry_run=0, owner=None, group=None, logger=None):"""Create an archive file (eg. zip or tar).

'base_name' is the name of the file to create, minus any format-specific

extension; 'format' is the archive format: one of "zip", "tar", "bztar"

or "gztar".

'root_dir' is a directory that will be the root directory of the

archive; ie. we typically chdir into 'root_dir' before creating the

archive.? 'base_dir' is the directory where we start archiving from;

ie. 'base_dir' will be the common prefix of all files and

directories in the archive.? 'root_dir' and 'base_dir' both default

to the current directory.? Returns the name of the archive file.

'owner' and 'group' are used when creating a tar archive. By default,

uses the current owner and group."""save_cwd=os.getcwd()ifroot_dirisnotNone:ifloggerisnotNone:

logger.debug("changing into '%s'", root_dir)

base_name=os.path.abspath(base_name)ifnotdry_run:

os.chdir(root_dir)ifbase_dirisNone:

base_dir=os.curdir

kwargs= {'dry_run': dry_run,'logger': logger}try:

format_info=_ARCHIVE_FORMATS[format]exceptKeyError:raiseValueError("unknown archive format '%s'"%format)

func=format_info[0]forarg, valinformat_info[1]:

kwargs[arg]=valifformat !='zip':

kwargs['owner'] =owner

kwargs['group'] =grouptry:

filename= func(base_name, base_dir, **kwargs)finally:ifroot_dirisnotNone:ifloggerisnotNone:

logger.debug("changing back to '%s'", save_cwd)

os.chdir(save_cwd)returnfilename

base_name:??? 壓縮打包后的文件名或者路徑名

format:????????? 壓縮或者打包格式"zip", "tar", "bztar"or "gztar"

root_dir :???????? 將哪個目錄或者文件打包(也就是源文件)

>>> shutil.make_archive('tarball','gztar',root_dir='copytree_test')

[root@slyoyo python_test]#ls -ltotal 12drwxr-xr-x. 3 root? root? 4096 May 14 19:36copytree_copy

drwxr-xr-x. 3 root? root? 4096 May 14 19:36copytree_test-rw-r--r--. 1 root? root? ? ? 0 May 14 21:12tarball.tar.gz-rw-r--r--. 1 python python? 79 May 14 05:17test1-rw-r--r--. 1 root? root? ? ? 0 May 14 19:10 test2


configparser模塊

#configparser用于處理特定格式的文件,其本質上是利用open來操作文件#下邊我們就創建這種特定格式配置文件,來操作以下這里模塊方法--------------test.conf----------------[section1]#configparser 會認定以中括號括住的為一個節點(node)k1 = 111#節點下,每一行配置文件為鍵值對存在(也可以寫成 k2:123)k2 =v2

k3= 123k4=True

k10= 100[section2]

k1=v1#封裝一個對象config =configparser.ConfigParser()#獲取所有節點(sections方法)config.read(‘test.conf‘,encoding=‘utf-8‘)

ret= config.sections()#獲取所有使用中括號的節點名稱print(ret)==> [‘section1‘,‘section2‘]#section方法返回一個列表,包含所有節點名稱#獲取指定節點下所有的鍵值對(items方法)ret = config.items(‘section1‘)#獲取文件的 key = v 或 key:v 等 鍵值對print(ret)==> [(‘k1‘,‘123‘), (‘k2‘,‘v2‘), (‘k3‘,‘123‘), (‘k4‘,‘True‘), (‘k10‘,‘100‘)]#獲取指定節點下所有的鍵(options方法)ret = config.options(‘section1‘)print(ret)==> [‘k1‘,‘k2‘,‘k3‘,‘k4‘,‘k10‘]#獲取指定節點下指定key的值 (get方法)#注意,下邊強制轉換不成功是會報錯的ret1 = config.get(‘section1‘,‘k1‘)#獲取section節點下的k1鍵對應的值ret2 = config.getint(‘section1‘,‘k3‘)#獲取section1節點下k3鍵對應的值,并將該值轉換為Int類型ret3 = config.getfloat(‘section1‘,‘k3‘)#獲取section1節點下k3鍵對應的值,并將該值轉換為float類型ret4 = config.getboolean(‘section1‘,‘k4‘)#獲取section1節點下k4鍵對應的值,并將該值轉換為boolean類型print(ret1,ret2,ret3,ret4)==> 111 123 123.0True### 檢查、刪除、添加節點 ####檢查節點(has_section方法)has_sec = config.has_section(‘section1‘)#檢查是否有section1節點print(has_sec)==> True#返回boolean值#添加節點 (add_section方法)config.add_section(‘SEC_1‘)#添加SEC_1節點config.write(open(‘test.conf‘,‘w‘))#將修改的內容寫入到test.conf#刪除節點 (remove_section方法)config.remove_section(‘SEC_1‘)#刪除SEC_1節點config.write(open(‘test.conf‘,‘w‘))#將修改的內容寫入到test.conf### 檢查、刪除、設置指定組內的鍵值對 ####檢查鍵值對 (has_option方法)has_opt = config.has_option(‘section1‘,‘k1‘)#檢查section1節點是否有k1鍵print(has_opt)#刪除鍵值對 (remove_option方法)config.remove_option(‘section1‘,‘k1‘)#刪除section1節點的k1鍵對應的鍵值對(這一行)config.write(open(‘test.conf‘,‘w‘))#將修改的內容寫入到test.conf#設置鍵值對 (set方法)config.set(‘section1‘,‘k10‘,"123")#設置(有修改,無添加)section1節點,k10=123config.write(open(‘test.conf‘,‘w‘))#將修改的內容寫入到test.conf#注意,我們配置文件被讀取后,放入內存中#我們剛剛所做的一切的增刪改,都是操作的內存中已加載的配置文件,#并沒有對實際文件有所改變,所以我們需要執行write方法寫入配置文件中

shutil

#將文件內容拷貝到另一個文件中shutil.copyfileobj(open(‘old.xml‘,‘r‘), open(‘new.xml‘,‘w‘))#拷貝文件shutil.copyfile(‘f1.log‘,‘f2.log‘)#拷貝文件和權限shutil.copy(‘f1.log‘,‘f2.log‘)#遞歸的去拷貝文件夾,并忽略拷貝pyc結尾,和tmp開頭的文件shutil.copytree(‘folder1‘,‘folder2‘, ignore=shutil.ignore_patterns(‘*.pyc‘,‘tmp*‘))#遞歸的去刪除文件shutil.rmtree(‘folder1‘)#遞歸的去移動文件,它類似mv命令,其實就是重命名。shutil.move(‘folder1‘,‘folder3‘)

壓縮與解壓(zipfile、tarfile)

#壓縮解壓 zipimportzipfile#壓縮z = zipfile.ZipFile(‘test.zip‘,‘w‘)#創建一個 以寫的方式寫入test.zip? 的對象z.write(‘xml_t2.xml‘)#添加xml_t2.xml文件到test.zipz.write(‘xml_t3.xml‘)#添加xml_t3.xml文件到test.zipz.close()#解壓z = zipfile.ZipFile(‘test.zip‘,‘r‘)

z.extractall()#解壓所有zip#z.extract()? # 指定解壓單個z.close()

#壓縮解壓 tarfileimporttarfile#壓縮tar = tarfile.open(‘your.tar‘,‘w‘)#創建一個 以寫的方式寫入test.tar? 的對象tar.add(‘xml_t2.xml‘,arcname=‘xml2.xml‘)#添加tar,并重命名xml2.xmltar.add(‘xml_t3.xml‘,arcname=‘xml3.xml‘)

tar.close()#解壓tar = tarfile.open(‘your.tar‘,‘r‘)

tar.extractall()#解壓全部,并可設置解壓地址tar.close()

subprocess

#call? 執行命令,返回狀態碼ret = subprocess.call(‘dir‘, shell=True)

ret= subprocess.call([‘ipconfig‘,‘/all‘], shell=False)#shell為False,需要傳入列表#check_call 執行命令,如果執行狀態碼ret = subprocess.check_call([‘ipconfig‘,‘/all‘])

ret= subprocess.check_call(‘exit 1‘,shell=True)#沒有exit命令,會拋異常#check_output 執行命令,如果狀態碼是0,則返回執行結果,否則拋異常subprocess.check_output([‘echo‘,‘hello world‘])

subprocess.check_output(‘echo hello‘, shell=True)#popen 方法obj = subprocess.Popen("mkdir t3", shell=True, cwd=‘/home/dev‘,)#跳轉到/home/dev,執行命令#popen 管道使用obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)#指定stdin、stdout、stderr流obj.stdin.write("print(1)\n")#寫入print(1) 的stdin流obj.stdin.write("print(2)")

obj.stdin.close()

cmd_out= obj.stdout.read()#讀取stdout 數據obj.stdout.close()

cmd_error= obj.stderr.read()#讀取stderr數據obj.stderr.close()#popen 讀取管道另一種方法out_err_list = obj.communicate()#生成一個列表,列表包含stdout和stderr數據,是一個綜合方法print(cmd_out)print(cmd_error)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容