python sh模块_python-shutil模块

一、简介

shutil是高级的 文件、文件夹、压缩包 处理模块

二使用

①、shutil.copyfileobj(fsrc, fdst[, length])

将文件内容拷贝到另一个文件中,可以指定文件大小。

注意:fsrc和fdst都是文件对象,拷贝的时候需要先把两个文件都打开

我们先来看下源码:

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)

实例:

import shutil

shutil.copyfileobj(open('test1.py', 'r'), open('test2.py', 'w'))

②、shutil.copyfile(src, dst)

拷贝文件

源码:

def copyfile(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):

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

实例:

import shutil

shutil.copyfile('test1.py', 'test2.py')

③、shutil.copymode(src,dst)

拷贝权限 内容、组、用户均不变

源码:

def copymode(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.

"""

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))

实例:

import shutil

shutil.copymode('test1.py', 'test2.py')

④、shutil.copystat(src,dst)

复制所有的状态信息,包括权限,组,用户,时间等

源码:

def copystat(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_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)

⑤、 shutil.copy(src, dst)

拷贝文件和权限

源码:

def copy(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.

"""

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

⑥shutil.copy2(src, dst)

拷贝文件和状态信息

源码:

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

⑦shutil.copytree(src, dst, symlinks=False, ignore=None)

递归的去拷贝文件

源码:

def copytree(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)

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

⑧、shutil.rmtree(path[, ignore_errors[, onerror]])

递归地去删除文件

源码:

def rmtree(path, ignore_errors=False, οnerrοr=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.

"""

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)

# Allow introspection of whether or not the hardening against symlink

# attacks is supported on the current platform

rmtree.avoids_symlink_attacks = _use_fd_functions

⑨、shutil.move(src, dst)

递归的移动文件

def move(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 = 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

查看源代码

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

压缩打包

base_name: 压缩包的文件名,也可以是压缩包的路径。

format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”

root_dir: 要压缩的文件夹路径(默认当前目录)

owner: 用户,默认当前用户

group: 组,默认当前组

logger: 用于记录日志,通常是logging.Logger对象

源码:

def make_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()

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

查看源代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值