shutil模块

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

 

常用的方法:

1.对象拷贝(将1个文件的内容拷贝到另一个文件)

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

源代码——

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)

通过源代码可以看到,这个方法其实就是通过循环读取文件内容,一次读取指定的长度(单位KB)再把读取到的内容写入目标文件。

演示:

把/etc/passwd拷贝到当前目录,执行如下代码段

#!/usr/bin/env python3

 

import shutil

 

shutil.copyfileobj(open('passwd','r'),open('new_passwd','w'))

执行结果:

alben@Python:~/Python_scripts$ ./file_obj.py

alben@Python:~/Python_scripts$ ls | grep passwd

new_passwd

passwd

alben@Python:~/Python_scripts$ diff passwd new_passwd

通过shell的diff比较文件,没有任何输出,说明文件内容完全一致。

 

2,文件拷贝

shutil.copyfile(src,dst)

源代码——

def copyfile(src, dst):

    """Copy data from src to dst"""

    if _samefile(src, dst):

        raise Error("`%s` and `%s` are the same file" % (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)

 

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

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

            copyfileobj(fsrc, fdst)

在源代码中,进行了文件比较,异常处理(防止文件不存在或者文件是设备文件,套接字文件等出现的异常)

拷贝的过程其实与copyfileobj()差不多。。。

演示:

把/etc/fstab文件拷贝到当前目录

在python解释器执行代码:

>>> import shutil

>>> shutil.copyfile('fstab','new_fstab')

'new_fstab'

在shell中比较文件内容:

alben@Python:~/Python_scripts$ diff fstab new_fstab

alben@Python:~/Python_scripts$

完全一致!

但是,拷贝过来的文件权限是根据当前用户的默认权限来设置的,所以根据需要还得拷贝权限

 

3,拷贝权限

shutil.copymode(src,dst)

源代码:

def copymode(src, dst):

    """Copy mode bits from src to dst"""

    if hasattr(os, 'chmod'):

        st = os.stat(src)

        mode = stat.S_IMODE(st.st_mode)

        os.chmod(dst, mode)

源码解析:

在这个”方法“中,需要借助两个模块中的其他“方法”!

  •  os模块
  •  stat模块

os.stat(src) 用于获取文件属性,我们可以测试在linux中对一个文件执行os.stat()方法

>>> a = os.stat('passwd')

>>> a

os.stat_result(st_mode=33188, st_ino=2505906, st_dev=2049, st_nlink=1, st_uid=1000, st_gid=1000, st_size=2523, st_atime=1496332301, st_mtime=1496332220, st_ctime=1496332220)

能够获取的属性,包括(mode,inode,times,gid,uid,size)

stat.S_IMODE(st.st_mode)

把os.stat()的结果中st_mode转换成unix 的模式表示方法

>>> stat.S_IMODE(a.st_mode)

420(其实这里的420不是shell中理解的那个420,具体是啥暂时未知)

演示:

alben@Python:~/Python_scripts$ ll a b

-rwxrwxrwx  1 alben alben    0 6月   2 00:36 a*

-rw-rw-r--  1 alben alben    0 6月   2 00:37 b

 

>>> import shutil

>>> shutil.copymode('a', 'b')

>>>

>>> exit()

alben@Python:~/Python_scripts$ ll a b

-rwxrwxrwx 1 alben alben 0 6月   2 00:36 a*

-rwxrwxrwx 1 alben alben 0 6月   2 00:37 b*

 

4,拷贝文件同时复制权限

shutil.copy(src,dst)

源代码:

def copy(src, dst):

    """Copy data and mode bits ("cp src dst").

 

    The destination may be a directory.

 

    """

    if os.path.isdir(dst):

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

    copyfile(src, dst)

    copymode(src, dst)

^_^,其实就是调用了copyfile()和copymode()

演示:

alben@Python:~/Python_scripts$ ll a

-rwxr-xr-x 1 root root 0 6月   2 17:27 a*

alben@Python:~/Python_scripts$ python3

Python 3.5.3 (default, Jan 19 2017, 14:11:04)

[GCC 6.3.0 20170118] on linux

Type "help", "copyright", "credits" or "license" for more information.

>>> import shutil

>>> shutil.copy('a','b')

'b'

>>> exit()

alben@Python:~/Python_scripts$ ll a b

-rwxr-xr-x 1 root  root  0 6月   2 17:27 a*

-rwxr-xr-x 1 alben alben 0 6月   2 17:36 b*

查看文件的状态:

stat 命令,可以发现拷贝后的新文件与源文件的ctime,mtime是不同的,如果要想这两个时间也拷贝,就需要copystat方法了

 

4,拷贝状态

shutil.copystat(src,dst)

源代码:

def copystat(src, dst):

    """Copy all stat info (mode bits, atime, mtime, flags) from src to dst"""

    st = os.stat(src)

    mode = stat.S_IMODE(st.st_mode)

    if hasattr(os, 'utime'):

        os.utime(dst, (st.st_atime, st.st_mtime))

    if hasattr(os, 'chmod'):

        os.chmod(dst, mode)

    if hasattr(os, 'chflags') and hasattr(st, 'st_flags'):

        try:

            os.chflags(dst, st.st_flags)

        except OSError as why:

            if (not hasattr(errno, 'EOPNOTSUPP') or

                why.errno != errno.EOPNOTSUPP):

                raise

拷贝文件的所有状态

 

5,移动文件

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

 

拷贝文件,如果在同一个路径下,就是rename重命名

原文地址:https://www.cnblogs.com/alben-cisco/p/6935717.html