背景
我们经常使用U盘来储存和备份文件。但是备份一个文件夹到U盘的时候, 如果文件夹之前已经放到U盘, 那么怎么办?
多数读者会选择替换U盘中原有的文件。但是:

首先, 这种方式速度慢。如果文件夹中有几十上百个文件, 全部复制到U盘, 还不如只复制最近修改的几个文件。
其次, 这种方法不能自动处理文件夹的变动。如新编辑的文件, 删除的文件, 以及重命名的文件等, 可能会导致重复文件等问题。当然, 一些读者会先删除U盘内原有的文件夹, 再复制一遍, 但速度仍较低。
另外, 在其他电脑修改了U盘的文件后, 如果继续替换, 修改会消失。

目录

  • 0.基础知识
  • 1.程序原理
  • 2.初次实现
  • 3.再次实现
  • 4.实现自动备份与同步

0.基础知识

  1. os.path.join(path,path2,path3,...)
    合并多个路径。与代码path+path2+path3+...的区别是不需考虑pathpath2的首尾是否带反斜杠\。所以, 建议拼接目录时os.path.join(), 不用+号。
  2. os.walk(path)
    遍历一个路径下的所有文件, 配合for循环使用。每次for迭代生成一个元组, 包含根目录名、子目录名、文件名。
  3. os.path.split(path)
    分割目录的最后一项和前面的项, 返回一个列表。如os.path.split("c:\\users\\admin")返回["c:\\users", "admin"]
  4. shutil.copy(src,dst)shutil.copy2(src,dst)
    src处的文件复制到dst
    区别: copy()只复制文件内容, 而copy2()会复制源文件的属性、修改日期、权限等信息到dst
  5. os.stat(file)
    获取文件的状态信息, 如大小、日期。返回一个os.stat_result对象, 例如os.stat("e:\\").st_mtime即可获得"e:\"的修改日期。

1.程序原理


假设有两个目录, 目录1是较新的, 就需要把目录1的修改应用到目录2中, 最终使目录1与目录2完全一致。
1.找出源目录(目录1)中新编辑的文件, 复制至目标目录(目录2)下。
2.找出目标目录中新编辑的文件, 并询问是否复制至源目录下。
3.删除目标目录中存在, 而源目录相同位置不存在的文件。

2.初次实现

初次实现的程序使用源目录更新目标目录。

import sys,os,shutil
def direc(path,dirs=True,files=True):#迭代器, 基于os.walk(), 列出path下的所有子目录和文件名。for root,_dirs,_files in os.walk(os.path.realpath(path)):if dirs:for name in _dirs:yield os.path.join(root, name)if files:for name in _files:yield os.path.join(root, name)
def copy2(src,dst):# 重写shutil.copy2()函数, 目标文件所在文件夹不存在时, 直接创建if not os.path.isdir(os.path.split(dst)[0]):os.makedirs(os.path.split(dst)[0],exist_ok=True)shutil.copy2(src,dst)
def normpath(path):# 重写os.path.normpath()函数path=os.path.normpath(path).strip('"')if path.endswith(':'):path += '\\'return path
src = normpath(input('输入源目录: '))
dst = normpath(input('输入目标目录: '))
for file in direc(src,dirs=False):dst_file = os.path.join(dst, file.replace(src,'')) # dst 拼接 源文件file去掉src的部分if os.path.isfile(dst_file):# 用源目录中新的文件替换旧的文件if os.stat(file).st_mtime > os.stat(dst_file).st_mtime:print('已复制:',file,dst_file)copy2(file,dst_file)elif os.stat(file).st_mtime < os.stat(dst_file).st_mtime:# 目标目录中文件较新时ans=input('是否复制 %s 到 %s ? (Y/N)' % (dst_file,file))if ans.lower().startswith('y'):copy2(dst_file,file)
    else: # 目标目录中旧文件不存在时print('已复制:',file,dst_file)copy2(file,dst_file)# 删除目标目录中存在, 而源目录相同位置不存在的文件
for file in direc(dst,dirs=False):if not os.path.isfile(os.path.join(src, file.replace(dst,'').lstrip('\\'))):ans=input('删除 %s ? (Y/N)' % (file))if ans.lower().startswith('y'):os.remove(file)print('已删除 '+file)os.system('pause') # 等待用户退出程序

3.再次实现

上述程序能很好地实现更新目录功能。但是, 程序不支持排除某些特定的文件。需要将需排除的文件列表放入一个文件中, 待程序读取。

  • fnmatch.fnmatch(文件名, 要匹配的通配符模式)
    检测文件名与模式是否匹配, 返回True或False。符号*表示匹配多个字符, ?表示匹配单个字符。如fnmatch.fnmatch("E:\\python.pyw","E:\\*.p?w")返回True。
import sys,os,shutil,fnmatch,tracebackdef read_ig(ignore_listfile): # 读取排除文件列表l=[]with open(ignore_listfile,encoding="utf-8") as f:for line in f:line = line.strip()if line[0] not in ('$','#'): # 忽略注释l.append(line)return ldef check_ig(file, ignore_list): # 判断文件是否应被排除for ig in ignore_list:if fnmatch.fnmatch(file,ig):return Truereturn Falsedef normpath(path):# --snip-- 代码同初次实现部分
def copy2(src,dst):# --snip--
def direc(path,dirs=True,files=True):# --snip--
def main():if len(sys.argv) >= 3: # 解析程序命令行参数 sys.argvsrc,dst = sys.argv[1:3]ignore_listfile = sys.argv[3] if len(sys.argv) >= 4 else Noneelse:print('用法:%s <源目录> <目标目录>' % sys.argv[0])src = normpath(input('输入源目录: ')).strip()dst = normpath(input('输入目标目录: ')).strip()default = '.gitignore' # 仅支持通配符格式if not os.path.isfile(default):default=Noneignore_listfile = input('排除文件的列表 (默认 %s): '%default) or defaultif ignore_listfile is not None: # 如果有排除列表文件ignore_list = read_ig(normpath(ignore_listfile).strip('"').strip())else:ignore_list = []all_=False;ignore_all=Falsefor file in direc(src,dirs=False):if check_ig(file, ignore_list):continuedst_file = os.path.join(dst + file[len(src):]) # 相当于file.replace(src,'')if os.path.isfile(dst_file):# 用源目录中新的文件替换旧的文件if os.stat(file).st_mtime > os.stat(dst_file).st_mtime:print('已复制:',file,dst_file)copy2(file,dst_file)elif os.stat(file).st_mtime < os.stat(dst_file).st_mtime:# 目标目录中文件较新时if all_:copy2(dst_file,file)elif not ignore_all:ans=input('是否复制 %s 到 %s ? [Y/N/A(All)/I(Ignore all)]'\% (dst_file,file))if ans.lower().startswith('y'):copy2(dst_file,file)elif ans.lower() in ('a','all'):all_=True;copy2(dst_file,file)elif ans.lower() in ('i','ignore all'):ignore_all=Trueelse:print('忽略 %s'%dst_file)else:# 目标目录中旧文件不存在时print('已复制:',file,dst_file)copy2(file,dst_file)# 删除目标目录中存在, 而源目录相同位置不存在的文件all_=False;ignore_all=Falsefor file in direc(dst,dirs=False):if check_ig(file, ignore_list):continueif not os.path.isfile(os.path.join(src, file[len(dst):].lstrip('\\'))):if all_:print('已删除 '+file)os.remove(file)elif not ignore_all:ans=input('删除 %s ? [Y/N/A(All)/I(Ignore all)]' % (file))if ans.lower().startswith('y'):os.remove(file)elif ans.lower() in ('a','all'):all_=True;os.remove(file)elif ans.lower() in ('i','ignore all'):ignore_all=Trueelse:print('忽略 %s'%file)# 删除目标目录中存在, 而源目录不存在的空目录for dir_ in direc(dst,files=False):if check_ig(dir_, ignore_list):continueif not os.listdir(dir_)\and not os.path.isdir(os.path.join(src, dir_[len(dst):].lstrip('\\'))):os.removedirs(dir_)print('已删除空目录 %s'%dir_)if __name__=="__main__":try:main()except Exception:traceback.print_exc() # 显示错误消息if not 'pythonw' in os.path.split(sys.executable)[1]: #在pythonw.exe(如IDLE)中运行时不暂停os.system('pause')

4.实现自动备份与同步

实现自动备份同步的代码省去了获取input()的部分, 通过修改sys.stderr为其他打开的文件记录日志和其他错误消息。
新建一个文本文件, 保存为.pyw扩展名, 目的是避免.py文件运行时显示黑色的控制台窗口。在其中加入以下程序:

import sys,os,shutil,fnmatch,traceback
import time
def direc(path,dirs=True,files=True):# --snip-- 代码同上
def read_ig(ignore_listfile):# --snip--
def check_ig(file, ignore_list):# --snip--
def normpath(path):# --snip--
def copy2(src,dst):# --snip--
def main(src,dst,ignore_listfile=None,flag_replace_src=True,flag_delete=True):if ignore_listfile:ignore_list = read_ig(normpath(ignore_listfile).strip('"').strip())else:ignore_list = []all_=False;ignore_all=Falsefor file in direc(src,dirs=False):if check_ig(file, ignore_list):continuedst_file = os.path.join(dst + file[len(src):]) # 相当于file.replace(src,'')if os.path.isfile(dst_file):# 用源目录中新的文件替换旧的文件if os.stat(file).st_mtime > os.stat(dst_file).st_mtime:print('已复制:',file,dst_file, file=sys.stderr)copy2(file,dst_file)elif os.stat(file).st_mtime < os.stat(dst_file).st_mtime:# 目标目录中文件较新时if flag_replace_src:copy2(dst_file,file)else:# 目标目录中旧文件不存在时print('已复制:',file,dst_file, file=sys.stderr)copy2(file,dst_file)# 删除目标目录中存在, 而源目录相同位置不存在的文件all_=False;ignore_all=Falseif flag_delete:for file in direc(dst,dirs=False):if check_ig(file, ignore_list):continueif not os.path.isfile(os.path.join(src, file[len(dst):].lstrip('\\'))):print('已删除 '+file, file=sys.stderr)os.remove(file)# 删除目标目录中存在, 而源目录不存在的空目录for dir_ in direc(dst,files=False):if check_ig(dir_, ignore_list):continueif not os.listdir(dir_)\and not os.path.isdir(os.path.join(src, dir_[len(dst):].lstrip('\\'))):os.removedirs(dir_)print('已删除空目录 %s'%dir_, file=sys.stderr)if __name__=="__main__": # 判断是否作为主程序运行src = "E:\\python"dst = "F:\\python-备份" # 可以是外部存储目录(如U盘)ig = None # 排除列表文件flag_replace_src=Trueflag_delete=Trueinterval = 300 # 秒sys.stderr = open("E:\\PyBackup.log","w",encoding="utf-8") # 不设为utf=8可能无法编码汉字while True:try:if os.path.isdir(dst): # 如果目标目录存在(即已插上U盘)print("==在 %s 开始备份==" % time.asctime(),file=sys.stderr)main(src,dst,ig,flag_replace_src,flag_delete)print("==备份完成 %s==\n" % time.asctime(),file=sys.stderr)except Exception:traceback.print_exc() # 将错误消息写入sys.stderr(即日志)sys.stderr.flush()time.sleep(interval)

将上述.pyw文件复制到C:\Users\<你的用户名>\AppData\Roaming\Microsoft\Windows\开始菜单\程序\启动这个目录, 就可以在开机时自动启动备份程序。

Python os模块 设计文件夹自动备份、同步工具相关推荐

  1. python os复制文件_使用python os模块复制文件到指定文件夹的方法

    复制一个文件夹的文件到指定目录下 import os import shutil import time start_time = time.time() # 需要被复制的文件夹 old_path = ...

  2. Python os模块文件操作(一)

    Python os模块文件操作(一) 一.文件描述符 在使用代码对文件进行操作时,为了指定操作的文件,避免不了要使用文件描述符,所以我们先介绍什么是文件描述符. 操作系统为了高效管理已经被打开的文件, ...

  3. Python OS模块和文件处理

    Python OS模块和文件处理 文件处理 1. 打开和关闭文件 2. 读&写 3. 文件定位 OS模块 1. OS模块简介: 2. OS模块常用函数 3. OS模块常用方法实战 4. 例题练 ...

  4. 转载: Python os 模块的功能以及子函数介绍

    原文链接: python之os模块 - 程序生(Codey) - 博客园 https://www.cnblogs.com/cxscode/p/8085326.html 一.Python OS模块介绍 ...

  5. python系统-Python OS模块常用功能 中文图文详解

    一.Python OS模块介绍 OS模块简单的来说它是一个Python的系统编程的操作模块,可以处理文件和目录这些我们日常手动需要做的操作. 可以查看OS模块的帮助文档: >>> i ...

  6. Python学习笔记四(Python OS模块)

    Python os模块提供了一个统一的操作系统接口函数,通过python os模块可以实现对系统本身的命令,文件,目录进行操作,官方参考文档( http://docs.python.org/libra ...

  7. Python os模块文件操作(二)

    Python os模块文件操作(二) os模块对文件夹和文件的操作很多.可以先看: https://blog.csdn.net/weixin_43790276/article/details/9867 ...

  8. Python os模块 -Python系统编程中的操作模块

    Python os模块 -Python系统编程中的操作模块 用途:处理(文件与目录)操作 以下为简单的常用操作 import os 导入os模块 help(os) 查看os模块帮助文档 os.name ...

  9. python os模块下载_Python OS模块目录文件处理

    Python编程语言优势特点比较突出,在Python语言中,有一种标准模块叫OS模块,Python OS模块包含普遍的操作系统功能,如果你希望你的程序能够与平台无关的话,这个模块尤为重要,它允许一个程 ...

最新文章

  1. python pandas DataFrame 替换 NaN 值 和 删除 NaN 所在的行。
  2. 关于strutsdemo实例的理解
  3. 线性表adt的c语言表达,抽象数据类型定义(ADT)
  4. vue和layui哪个更好用_幕布和Mind+思维导图哪个更好用?
  5. 通过spark-submit,本地测试SparkStreaming
  6. Java中List、Map、Set三个接口,存取元素时,各有什么特点?
  7. 函数式编程 -- 测试题集
  8. IP得到天气预报(3)———XML中CDATA的提取
  9. java的constructor怎么用,Java Constructor getDeclaringClass()用法及代码示例
  10. Linux NGINX 主备,使用keepalived实现主备(以nginx为例)
  11. 9.6.1 三维数据可视化之平面图
  12. IIS7.X上传文件大小受限制解决方法
  13. oracle里的关键字有哪些,oracle中的一些关键字
  14. matlab2c使用c++实现matlab函数系列教程-sin函数
  15. 最简单的小程序怎么做?
  16. 四、 vSphere 6.7 U1(四):部署VCSA
  17. Flash Builder实用快捷键集锦
  18. Guake安装配置:下拉式Gnome桌面终端
  19. 如何清理Windows XP冗余文件【绿色系统收藏】
  20. 关于安卓开发,在鸿蒙系统应用时,File读取文被拒绝访问的解决方案

热门文章

  1. 数字逻辑大作业----数字时钟
  2. 免费的发外链友链的简单易操作思路
  3. 玉米社:外链、反链、内链、友链的区别与联系详解
  4. 这些个辞职申请,在下佩服至极
  5. SpringBoot多数据源配置
  6. [JavaScript] CocosCreator 中国象棋 —— 棋子移动
  7. Android开发——自动连接指定SSID的wifi热点(不加密/加密)
  8. 【线性代数】4-1:四个正交子空间(Orthogonality of the Four Subspace)
  9. 【热门主题:海贼王路飞免费主题】
  10. iPhone忘记密码,怎么开机?