这是五一期间,参照知乎上一篇的文章十行代码--用python写一个USB病毒》写成的,最初只是单纯的想写成死循环,直到文件占满硬盘为止,第一个遇到的问题是,拷贝到硬盘之后,由于要无限次拷贝,所以每次的文件夹的名字不能重复,对于这个问题,开始是采用追加的方式,比如第一个文件夹叫udisk_bakcup,第二个文件夹就叫udisk_backup_demo,第三个叫udisk_backup_demo_demo...看到的效果是:

这样肯定是不行的,因为文件夹名字的长度好像不能超过256个字节,受一位开发同学的启发,用时间戳来表示,看到的效果明显好多了

后来想,能不能不写死循环,而是根据用户的需要选择拷贝次数,能不能做成界面,一切在遇到tkinter和PyInstaller后得到了解决

界面化实现过程不太容易,遇到的问题参见:《解决: PyInstaller打包后exe文件打开时出现failed to execute script

生成图标后,还有一个问题:打包后生成的exe文件打开后,工具左上角的图标并没有加载进来,而直接运行代码是ok的(见上图)

利用if判断,做了一定的容错处理,那时我不知道还可以用正则做这件事,如果知道,可能会简化一下代码

再后来发现当U盘中的目录很大时,几百M到几个G,拷贝容易出现卡死的情况,可能由于是单线程,所以想着用多线程或协程的方法优化一下,谁知后来越来越忙就放下了,等到有机会再试一把

这个工具还是很好用的,可以将U盘所有的目录和文件拷进硬盘,自动在硬盘上创建一个文件夹来存储这些拷贝数据,还可以按照需要拷贝多份(默认是拷贝一份)

现将源码附上:

  1. '''
  2. version v1.0
  3. 1. 实现了简单的pycharm运行功能
  4. 2. 利用追加目录名的方法来实现添加n个目录,但受到目录名长度的限制
  5.  
  6. version v2.0
  7. 1. 利用时间戳表示目录名
  8. 2. 利用tkinter实现了简单的GUI
  9.  
  10. version v3.0
  11. 1. 修改了部分GUI界面字符
  12. 2. 利用datetime获取当前时间,并转化为字符串形式添加到目录
  13.  
  14. version v4.0
  15. 1. 修改了部分GUI界面
  16.  
  17. version v5.0
  18. 1. 限定了udisk_path, backup_path和num的范围
  19. 2. 对以上输入进行容错处理
  20. 3. 添加了计算程序运行时间的功能
  21. 4. 添加了输入提示
  22. 5. 不区分盘符的大小写
  23.  
  24. version v6.0
  25. 1. 更新了使用说明和字体、颜色
  26. 2. 更新了软件图标
  27. 3. 解决盘符为G:/的U盘不插入,不会弹出提示的问题。即在异常处理里增加了一个PermissionError的异常。
  28.  
  29. version v6.1
  30. 1. 解决了当U盘盘符为g:/, h:/时,弹出的错误信息
  31. 2. 给拷贝次数一个默认值1
  32. 3. 更新了使用说明
  33. '''
  34.  
  35. import os, shutil, sys
  36. import time, datetime, tkinter
  37. import tkinter.messagebox as mb
  38.  
  39. class Udisk:
  40.  
  41. def __init__(self, backup_path = "D:/", udisk_path = "H:/", num = 1):
  42. self.backup_path = backup_path
  43. self.udisk_path = udisk_path
  44. self.num = num
  45.  
  46. def resource_path(self, relative):
  47. if hasattr(sys, "_MEIPASS"):
  48. return os.path.join(sys._MEIPASS, relative)
  49. return os.path.join(relative)
  50.  
  51. def copy_GUI(self):
  52. root = tkinter.Tk()
  53. root.title("U盘拷贝小工具 v6.1")
  54. root.geometry("400x260")
  55. icopath = self.resource_path(r"favicon-20180501101520441.ico")
  56. if os.path.exists(icopath):
  57. root.iconbitmap(icopath)
  58.  
  59. tkinter.Label(root, text = "U盘盘符(如G:/)", font = ("华文中宋", 12)).grid(row = 0)
  60. tkinter.Label(root, text = "拷贝目录(如D:/)", font = ("华文中宋", 12)).grid(row = 1)
  61. tkinter.Label(root, text = "拷贝次数(如3)", font = ("华文中宋", 12)).grid(row = 2)
  62.  
  63. self.input_1 = tkinter.Entry(root)
  64. self.input_2 = tkinter.Entry(root)
  65. self.input_3 = tkinter.Entry(root)
  66.  
  67. self.input_3.insert(10, ")
  68.  
  69. self.input_1.grid(row = 0, column = 1)
  70. self.input_2.grid(row = 1, column = 1)
  71. self.input_3.grid(row = 2, column = 1)
  72.  
  73. tkinter.Button(root, text = "ok", font = ("Arial", 12), background = "MediumSlateBlue", command = self.run).grid(row=3, pady=15, column=0)
  74. tkinter.Button(root, text = "exit", font = ("Arial", 12), background = "DarkGray", command = root.quit).grid(row=3, pady=15, column=1)
  75.  
  76. tkinter.Label(root, text = "使用说明:\n1.本软件适用于windows系统;\n2.默认以/作为目录分隔符;\n3.目录名不能包含特殊字符\n4.默认拷贝次数为1", justify = "left", font = ("隶书", 12), pady = 20).grid(row = 4)
  77.  
  78. root.mainloop()
  79.  
  80. def dirExists(self):
  81. while True:
  82. if os.path.exists(self.backup_path) == True:
  83. print("copytree方法的路径%s不能是已存在的!" % self.backup_path)
  84. now = datetime.datetime.now()
  85. self.backup_path += now.strftime('%Y-%m-%d %H-%M-%S.%f')
  86. print("程序自动将路径重命名为: %s" % self.backup_path)
  87. return self.dirExists()
  88. else:
  89. break
  90.  
  91. def copyUdisk(self):
  92. try:
  93. self.flag = True
  94. file_list = []
  95. content = os.listdir(self.udisk_path)
  96. self.dirExists()
  97. except FileNotFoundError:
  98. print("对不起,U盘不存在,请插入U盘重试! ")
  99. return False
  100. except PermissionError:
  101. print("对不起,U盘不存在,请插入U盘重试! ")
  102. self.flag = False
  103. else:
  104. for item_1 in content:
  105. if os.path.isfile(os.path.join(self.udisk_path, item_1)) == False:
  106. shutil.copytree(os.path.join(self.udisk_path, item_1), self.backup_path + "/" + item_1)
  107. else:
  108. file_list.append(item_1)
  109. for item_2 in file_list:
  110. shutil.copy(os.path.join(self.udisk_path, item_2), self.backup_path + "/")
  111. print("已拷贝至", self.backup_path)
  112. return True
  113.  
  114. def run(self):
  115. time_1 = time.time()
  116. try:
  117. self.udisk_path = self.input_1.get()
  118. self.backup_path = self.input_2.get()
  119. self.num = self.input_3.get()
  120. print(self.num)
  121. standard_backup_path = ["C:/", "c:/", "D:/", "d:/", "E:/", "e:/", "F:/", "f:/"]
  122. standard_udisk_path = ["G:/", "g:/", "H:/", "h:/"]
  123. if self.backup_path[0:3] in standard_backup_path and self.udisk_path[:] in standard_udisk_path and (type(int(self.num)) == int or self.num == ""):
  124. for i in range(int(self.num)):
  125. my_copy = Udisk(self.backup_path, self.udisk_path, self.num)
  126. if my_copy.copyUdisk() == False:
  127. mb.showerror("错误", "对不起,U盘不存在,请插入U盘重试! ")
  128. break
  129. elif my_copy.flag == False:
  130. mb.showerror("错误", "对不起,U盘盘符不对应,请重试! ")
  131. break
  132. elif i == (int(self.num) - 1):
  133. time_2 = time.time()
  134. total_time = time_2 - time_1
  135. output = "已拷贝成功:)"
  136. mb.showinfo("结果", output)
  137. mb.showinfo("共耗时", str(total_time)+"")
  138. elif self.udisk_path[:] not in standard_udisk_path:
  139. if self.udisk_path == "":
  140. mb.showerror("输入错误", "U盘盘符不能为空,请重试! ")
  141. else:
  142. mb.showerror("输入错误", "输入U盘盘符错误,请重试! ")
  143. elif self.backup_path[0:3] not in standard_backup_path:
  144. if self.backup_path == "":
  145. mb.showerror("输入错误", "拷贝目录不能为空,请重试! ")
  146. else:
  147. mb.showerror("输入错误", "输入拷贝目录错误,请重试! ")
  148. except ValueError:
  149. mb.showerror("输入错误", "输入拷贝次数错误,请重试! ")
  150.  
  151. mycopy = Udisk()
  152. mycopy.copy_GUI()

自己动手写一个U盘拷贝小工具的更多相关文章

  1. 用 C# 写一个 Redis 数据同步小工具

    用 C# 写一个 Redis 数据同步小工具 Intro 为了实现 redis 的数据迁移而写的一个小工具,将一个实例中的 redis 数据同步到另外一个实例中.(原本打算找一个已有的工具去做,找了一 ...

  2. 动手写一个简单版的谷歌TPU-指令集

    系列目录 谷歌TPU概述和简化 基本单元-矩阵乘法阵列 基本单元-归一化和池化(待发布) TPU中的指令集 SimpleTPU实例: (计划中) 拓展 TPU的边界(规划中) 重新审视深度神经网络中的 ...

  3. 死磕 java线程系列之自己动手写一个线程池

    欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. (手机横屏看源码更方便) 问题 (1)自己动手写一个线程池需要考虑哪些因素? (2)自己动手写 ...

  4. 动手写一个简单的Web框架(Werkzeug路由问题)

    动手写一个简单的Web框架(Werkzeug路由问题) 继承上一篇博客,实现了HelloWorld,但是这并不是一个Web框架,只是自己手写的一个程序,别人是无法通过自己定义路由和返回文本,来使用的, ...

  5. 动手写一个简单版的谷歌TPU-矩阵乘法和卷积

    谷歌TPU是一个设计良好的矩阵计算加速单元,可以很好的加速神经网络的计算.本系列文章将利用公开的TPU V1相关资料,对其进行一定的简化.推测和修改,来实际编写一个简单版本的谷歌TPU.计划实现到行为 ...

  6. 死磕 java同步系列之自己动手写一个锁Lock

    问题 (1)自己动手写一个锁需要哪些知识? (2)自己动手写一个锁到底有多简单? (3)自己能不能写出来一个完美的锁? 简介 本篇文章的目标一是自己动手写一个锁,这个锁的功能很简单,能进行正常的加锁. ...

  7. 开源一个Mac漂亮的小工具 PPRows for Mac, 在Mac上优雅的计算你写了多少行代码

    开源一个Mac漂亮的小工具 PPRows for Mac, 在Mac上优雅的计算你写了多少行代码. 开源地址: https://github.com/jkpang/PPRows

  8. 自己动手写一个服务网关-java

    自己动手写一个服务网关 原文链接:https://www.cnblogs.com/bigben0123/p/9252444.html 引言 什么是网关?为什么需要使用网关? 如图所示,在不使用网关的情 ...

  9. 动手写一个简单的Web框架(模板渲染)

    动手写一个简单的Web框架(模板渲染) 在百度上搜索jinja2,显示的大部分内容都是jinja2的渲染语法,这个不是Web框架需要做的事,最终,居然在Werkzeug的官方文档里找到模板渲染的代码. ...

随机推荐

  1. 斯坦福大学Andrew Ng - 机器学习笔记(1) -- 单变量&多变量线性回归

    大概用了一个月,Andrew Ng老师的机器学习视频断断续续看完了,以下是个人学习笔记,入门级别,权当总结.笔记难免有遗漏和误解,欢迎讨论. 鸣谢:中国海洋大学黄海广博士提供课程视频和个人笔记,在此深 ...

  2. Could not create ServerSocket on address 0.0.0.0/0.0.0.0:9083

    遇到这种情况大家都找不到头绪,是因为你开始运行了hive的metastore,可以输入jps 然后出现如下: 红线所示就是hive metastore的进程 为了重新启动,需要把这个进杀掉: kill ...

  3. active scaffold

    模板文件路径:/.rvm/gems/ruby-2.2.3/gems/active_scaffold-3.5.3/app/views/active_scaffold_overrides

  4. b和strong,i与em的区别

    html语义化标签: 1)title与h1的区别 title与H1是不能划等号的 1.H1是大标题的意思.一般出现网页文章页面,作用如同一张报纸的大标题,使用读者在没看内容之前就 大概了解本文的旨意, ...

  5. 【CodeChef】Small factorials(BigInteger笔记)

    You are asked to calculate factorials of some small positive integers. Input An integer t, 1<=t&l ...

  6. linux基础三---网络基础&软件包管理

    一 ifconfig:显示所有正在启动的网卡的详细信息或设定系统中网卡的IP地址. ifconfig eno16777736 down/up   关闭/开启 eno16777736 网卡 ifconf ...

  7. Django框架之cookie和session及开发登录功能

    1.cookie是什么? Web应用程序是使用HTTP协议传输数据的.HTTP协议是无状态的协议.一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接.这就意味着服务器无法从 ...

  8. 在各种Linux发行版上安装Git的教程

    Git是一个流行的开源版本控制系统(VCS),最初是为Linux环境开发的.跟CVS或者SVN这些版本控制系统不同的是,Git的版本控制被认为是“分布式的”,某种意义上,git的本地工作目录可以作为一 ...

  9. MyBatis联合查询association使用

    1.需求 两张表 channels(频道表)  member(会员表) 频道表里面有会员id,查询频道列表的时候需要关联查询出会员的名称,头像等信息 . 2.channels.xml定义,配置主要在这 ...

  10. 【BZOJ2733】永无乡[HNOI2012](splay启发式合并or线段树合并)

    题目大意:给你一些点,修改是在在两个点之间连一条无向边,查询时求某个点能走到的点中重要度第k大的点.题目中给定的是每个节点的排名,所以实际上是求第k小:题目求的是编号,不是重要度的排名.我一开始差点被 ...