小白的Python之路 day5 shutil模块

shutil模块

一、主要用途

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

二、常用方法详解

1、shutil.copyfileobj(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)

2、shutil.copyfile(src, dst)         #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)

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)

4、shutil.copystat(src, dst)

功能:拷贝文件的状态信息,如:mode bits, atime, mtime, flags

 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, why:
             for err in 'EOPNOTSUPP', 'ENOTSUP':
                 if hasattr(errno, err) and why.errno == getattr(errno, err):
                     break
             else:
                 raise

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

6、shutil.copy2(src, dst)

功能:拷贝文件和文件的状态信息

 def copy2(src, dst):
     """Copy data and all stat info ("cp -p 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)
     copystat(src, dst)

7、shutil.copytree(src, dst)

功能:递归的去拷贝文件

 def copytree(src, dst, symlinks=False, ignore=None):
     """Recursively copy a directory tree using copy2().

     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.

     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.

     XXX Consider this example code rather than the ultimate tool.

     """
     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 symlinks and os.path.islink(srcname):
                 linkto = os.readlink(srcname)
                 os.symlink(linkto, dstname)
             elif os.path.isdir(srcname):
                 copytree(srcname, dstname, symlinks, ignore)
             else:
                 # Will raise a SpecialFileError for unsupported file types
                 copy2(srcname, dstname)
         # catch the Error from the recursive copytree so that we can
         # continue with other files
         except Error, err:
             errors.extend(err.args[0])
         except EnvironmentError, why:
             errors.append((srcname, dstname, str(why)))
     try:
         copystat(src, dst)
     except OSError, why:
         if WindowsError is not None and isinstance(why, WindowsError):
             # Copying file access times may fail on Windows
             pass
         else:
             errors.append((src, dst, str(why)))
     if errors:
         raise Error, errors

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

功能:递归的去删除文件

 def rmtree(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 os.listdir, os.remove, or os.rmdir;
     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
     try:
         if os.path.islink(path):
             # 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())
         # can't continue even if onerror hook returns
         return
     names = []
     try:
         names = os.listdir(path)
     except os.error, err:
         onerror(os.listdir, path, sys.exc_info())
     for name in names:
         fullname = os.path.join(path, name)
         try:
             mode = os.lstat(fullname).st_mode
         except os.error:
             mode = 0
         if stat.S_ISDIR(mode):
             rmtree(fullname, ignore_errors, onerror)
         else:
             try:
                 os.remove(fullname)
             except os.error, err:
                 onerror(os.remove, fullname, sys.exc_info())
     try:
         os.rmdir(path)
     except os.error:
         onerror(os.rmdir, path, sys.exc_info())

9、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.

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

三、压缩包,解压

1、shutil.make_archive((base_name, format, root_dir=None,base_dir=None,verbose=0,dry=0,owner=None,group=None,logger=None)

功能:创建压缩包并且返回文件路径,例如:zip,tar

base_name : 压缩包的文件名,也可以是压缩包的路径。只是文件名,则保存当前目录,否则保存到指定路径。

如:www                       ==>保存到当前路径

   :C:\Users\Administrator\www  ===>保存至C:\Users\Administrator\

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

2、zipfile

功能:以zip的形式压缩文件,注意了这个只能压缩文件,不能压缩目录,如果压缩,也只能显示空目录。

 import zipfile

 # 压缩
 z = zipfile.ZipFile('qianduoduo.zip', 'w')
 z.write('info')  #写入当前环境变量内的文件
 z.write('shutil_test.py')
 z.close()   #关闭

 # 解压
 z = zipfile.ZipFile('qianduoduo.zip', 'r')
 z.extractall()   #解压所有压缩包内的文件
 z.close()

3、tarfile

功能:以tar的形式打包文件,这边能打包所以文件,包括目录

 import tarfile

 # 压缩
 import tarfile
 tar = tarfile.open("钱多多.tar","w")
 tar.add("f:haha\钱多多.zip")
 tar.add("f:haha\钱多多1.tar")
 tar.close()
 #解压
 tar = tarfile.open("钱多多.tar",'r')
 tar.extractall()  #可以添加路径
 tar.close()

小结:

  1、tar打包不会压缩文件,所以文件的大小没有变

  2、zip才会压缩,所以压缩后的文件大小会变小

  3、一般情况下是先打包再压缩

上一篇:C++反汇编(一)


下一篇:Multipart/form-data POST文件上传详解