高级的文件、文件夹、压缩包处理模块
常用的方法:
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重命名