视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Python中shutil模块的常用文件操作函数用法示例
2020-11-27 14:29:01 责编:小采
文档


os模块提供了对目录或者文件的新建/删除/查看文件属性,还提供了对文件以及目录的路径操作。比如说:绝对路径,父目录…… 但是,os文件的操作还应该包含移动 复制 打包 压缩 解压等操作,这些os模块都没有提供。
而本文所讲的shutil则就是对os中文件操作的补充。--移动 复制 打包 压缩 解压,
shutil函数功能:
1 shutil.copyfileobj(fsrc, fdst[, length=16*1024])
copy文件内容到另一个文件,可以copy指定大小的内容
先来看看其源代码。

def copyfileobj(fsrc, fdst, length=16*1024):
 """copy data from file-like object fsrc to file-like object fdst"""
 while 1:
 buf = fsrc.read(length)
 if not buf:
 break
 fdst.write(buf)

注意! 在其中fsrc,fdst都是文件对象,都需要打开后才能进行复制操作

import shutil
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

def copyfile(src, dst, *, follow_symlinks=True):
 if _samefile(src, dst):
 raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
 for fn in [src, dst]:
 try:
 st = os.stat(fn)
 except OSError:
 # File most likely does not exist
 pass
 else:
 # XXX What about other special files? (sockets, devices...)
 if stat.S_ISFIFO(st.st_mode):
 raise SpecialFileError("`%s` is a named pipe" % fn)
 if not follow_symlinks and os.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)
 return dst

shutil.copyfile('name','name_copy_2')
#一句就可以实现复制文件内容

3 shutil.copymode(src,dst)
仅copy权限,不更改文件内容,组和用户。

def copymode(src, dst, *, follow_symlinks=True):
 if not follow_symlinks and os.path.islink(src) and os.path.islink(dst):
 if hasattr(os, 'lchmod'):
 stat_func, chmod_func = os.lstat, os.lchmod
 else:
 return
 elif hasattr(os, 'chmod'):
 stat_func, chmod_func = os.stat, os.chmod
 else:
 return
 st = stat_func(src)
 chmod_func(dst, stat.S_IMODE(st.st_mode))

先看两个文件的权限

[root@slyoyo python_test]# ls -l
total 4
-rw-r--r--. 1 root root 79 May 14 05:17 test1
-rwxr-xr-x. 1 root root 0 May 14 19:10 test2

运行命令

>>> import shutil
>>> shutil.copymode('test1','test2')

查看结果

[root@slyoyo python_test]# ls -l
total 4
-rw-r--r--. 1 root root 79 May 14 05:17 test1
-rw-r--r--. 1 root root 0 May 14 19:10 test2

当我们将目标文件换为一个不存在的文件时报错

>>> shutil.copymode('test1','test3') 
Traceback (most recent call last):
 File "", line 1, in 
 File "/usr/local/python/lib/python3.4/shutil.py", line 132, in copymode
 chmod_func(dst, stat.S_IMODE(st.st_mode))
FileNotFoundError: [Errno 2] No such file or directory: 'test233'

4 shutil.copystat(src,dst)
复制所有的状态信息,包括权限,组,用户,时间等

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

 def _nop(*args, ns=None, follow_symlinks=None):
 pass
 # follow symlinks (aka don't not follow symlinks)
 follow = follow_symlinks or not (os.path.islink(src) and os.path.islink(dst))
 if follow:
 # use the real function if it exists
 def lookup(name):
 return getattr(os, name, _nop)
 else:
 # use the real function only if it exists
 # *and* it supports follow_symlinks
 def lookup(name):
 fn = getattr(os, name, _nop)
 if fn in os.supports_follow_symlinks:
 return fn
 return _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)
 except NotImplementedError:
 # 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.)
 pass
 if hasattr(st, 'st_flags'):
 try:
 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
 except OSError as why:
 for err in 'EOPNOTSUPP', 'ENOTSUP':
 if hasattr(errno, err) and why.errno == getattr(errno, err):
 break
 else:
 raise
 _copyxattr(src, dst, follow_symlinks=follow)


5 shutil.copy(src,dst)
复制文件的内容以及权限,先copyfile后copymode

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

 if os.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)
 return dst


6 shutil.copy2(src,dst)
复制文件的内容以及文件的所有状态信息。先copyfile后copystat

def copy2(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".
 """
 if os.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)
 return dst


7 shutil.copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,ignore_dangling_symlinks=False)
递归的复制文件内容及状态信息

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

 names = os.listdir(src)
 if ignore is not None:
 ignored_names = ignore(src, names)
 else:
 ignored_names = set()
 os.makedirs(dst)
 errors = []
 for name in names:
 if name in ignored_names:
 continue
 srcname = os.path.join(src, name)
 dstname = os.path.join(dst, name)
 try:
 if os.path.islink(srcname):
 linkto = os.readlink(srcname)
 if symlinks:
 # 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=not symlinks)
 else:
 # ignore dangling symlink if the flag is on
 if not os.path.exists(linkto) and ignore_dangling_symlinks:
 continue
 # otherwise let the copy occurs. copy2 will raise an error
 if os.path.isdir(srcname):
 copytree(srcname, dstname, symlinks, ignore,
 copy_function)
 else:
 copy_function(srcname, dstname)
 elif os.path.isdir(srcname):
 copytree(srcname, dstname, symlinks, ignore, copy_function)
 else:
 # Will raise a SpecialFileError for unsupported file types
 copy_function(srcname, dstname)
 # catch the Error from the recursive copytree so that we can
 # continue with other files
 except Error as err:
 errors.extend(err.args[0])
 except OSError as why:
 errors.append((srcname, dstname, str(why)))
 try:
 copystat(src, dst)
 except OSError as why:
 # Copying file access times may fail on Windows
 if getattr(why, 'winerror', None) is None:
 errors.append((src, dst, str(why)))
 if errors:
 raise Error(errors)
 return dst
# version vulnerable to race conditions

[root@slyoyo python_test]# tree copytree_test/
copytree_test/
└── test
 ├── test1
 ├── test2
 └── hahaha
[root@slyoyo test]# ls -l
total 0
-rw-r--r--. 1 python python 0 May 14 19:36 hahaha
-rw-r--r--. 1 python python 0 May 14 19:36 test1
-rw-r--r--. 1 root root 0 May 14 19:36 test2
>>> shutil.copytree('copytree_test','copytree_copy')
'copytree_copy'
[root@slyoyo python_test]# ls -l
total 12
drwxr-xr-x. 3 root root 4096 May 14 19:36 copytree_copy
drwxr-xr-x. 3 root root 4096 May 14 19:36 copytree_test
-rw-r--r--. 1 python python 79 May 14 05:17 test1
-rw-r--r--. 1 root root 0 May 14 19:10 test2
[root@slyoyo python_test]# tree copytree_copy/
copytree_copy/
└── test
 ├── hahaha
 ├── test1
 └── test2


8 shutil.rmtree(path, ignore_errors=False, onerror=None)
递归地删除文件

def rmtree(path, ignore_errors=False, onerror=None):

 if ignore_errors:
 def onerror(*args):
 pass
 elif onerror is None:
 def onerror(*args):
 raise
 if _use_fd_functions:
 # While the unsafe rmtree works fine on bytes, the fd based does not.
 if isinstance(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)
 except Exception:
 onerror(os.lstat, path, sys.exc_info())
 return
 try:
 fd = os.open(path, os.O_RDONLY)
 except Exception:
 onerror(os.lstat, path, sys.exc_info())
 return
 try:
 if os.path.samestat(orig_st, os.fstat(fd)):
 _rmtree_safe_fd(fd, path, onerror)
 try:
 os.rmdir(path)
 except OSError:
 onerror(os.rmdir, path, sys.exc_info())
 else:
 try:
 # symlinks to directories are forbidden, see bug #1669
 raise OSError("Cannot call rmtree on a symbolic link")
 except OSError:
 onerror(os.path.islink, path, sys.exc_info())
 finally:
 os.close(fd)
 else:
 return _rmtree_unsafe(path, onerror)


9 shutil.move(src, dst)
递归的移动文件

def move(src, dst):

 real_dst = dst
 if os.path.isdir(dst):
 if _samefile(src, dst):
 # We might be on a case insensitive filesystem,
 # perform the rename anyway.
 os.rename(src, dst)
 return
 real_dst = os.path.join(dst, _basename(src))
 if os.path.exists(real_dst):
 raise Error("Destination path '%s' already exists" % real_dst)
 try:
 os.rename(src, real_dst)
 except OSError:
 if os.path.islink(src):
 linkto = os.readlink(src)
 os.symlink(linkto, real_dst)
 os.unlink(src)
 elif os.path.isdir(src):
 if _destinsrc(src, dst):
 raise Error("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)
 return real_dst


10 make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,dry_run=0, owner=None, group=None, logger=None)

压缩打包

def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
 dry_run=0, owner=None, group=None, logger=None):

 save_cwd = os.getcwd()
 if root_dir is not None:
 if logger is not None:
 logger.debug("changing into '%s'", root_dir)
 base_name = os.path.abspath(base_name)
 if not dry_run:
 os.chdir(root_dir)
 if base_dir is None:
 base_dir = os.curdir
 kwargs = {'dry_run': dry_run, 'logger': logger}
 try:
 format_info = _ARCHIVE_FORMATS[format]
 except KeyError:
 raise ValueError("unknown archive format '%s'" % format)
 func = format_info[0]
 for arg, val in format_info[1]:
 kwargs[arg] = val
 if format != 'zip':
 kwargs['owner'] = owner
 kwargs['group'] = group
 try:
 filename = func(base_name, base_dir, **kwargs)
 finally:
 if root_dir is not None:
 if logger is not None:
 logger.debug("changing back to '%s'", save_cwd)
 os.chdir(save_cwd)
 return filename


base_name: 压缩打包后的文件名或者路径名
format: 压缩或者打包格式 "zip", "tar", "bztar"or "gztar"
root_dir : 将哪个目录或者文件打包(也就是源文件)

>>> shutil.make_archive('tarball','gztar',root_dir='copytree_test')
[root@slyoyo python_test]# ls -l
total 12
drwxr-xr-x. 3 root root 4096 May 14 19:36 copytree_copy
drwxr-xr-x. 3 root root 4096 May 14 19:36 copytree_test
-rw-r--r--. 1 root root 0 May 14 21:12 tarball.tar.gz
-rw-r--r--. 1 python python 79 May 14 05:17 test1
-rw-r--r--. 1 root root 0 May 14 19:10 test2

下载本文
显示全文
专题