/
portable_sync.py
189 lines (173 loc) · 7.29 KB
/
portable_sync.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import json
import os
import re
import psutil
import shutil
import hashlib
'''
@author: github/wolverinn
@date: 03/22/2019
requirements:
Python 3.x
psutil
setting.json
function:
Sync the files on computer to portable devices, including auto-update and deletion.
待改进:setting.json 可以直接放在U盘的同步文件夹中。setting.json可以直接不要U盘文件夹这一项,直接硬编码
TODO: setting.json can be directly put in the /sync folder in u-drive. setting.json can abandon the setting of u-drive folders, but hard-coding instead.
'''
'''
setting.json:
At the minimum, you need to complete the "computer_locations"
"computer_locations" is a list of locations in your computer that you want to sync
"portable_device_folder" is the location in the portable device where your sync folder exists, you can also leave it blank and a default sync folder will be created automatically
"ignore" is a list of suffixs to exclude those you don't want to sync
"override_updates": "y" means when some files have changed, it will be automatically updated without asking; "n" means otherwise
"override_delete": "y" means when some files no longer exist on the computer, automatically delete the files in the portable device without asking
'''
'''
先设置电脑中需要同步的文件夹的绝对路径
对应的U盘路径如果不设置则会自动检测U盘然后创建同步文件夹
ignore填文件后缀名,出现在ignore中的文件后缀不会同步
override_updates表示需要更新时是否询问
override_delete表示需要删除时是否询问
'''
sync_folder = "" # 移动设备的同步文件夹路径
portable_part = "" # 移动设备的盘符
global dir_list # 需要同步的所有文件夹(包括子文件夹)
# 获取移动设备的盘符,以及判断是否有移动设备插入,如没有则推出
disk = psutil.disk_partitions()
for single_disk in disk:
attr = single_disk.opts.split(",")
if "fixed" not in attr and "cdrom" not in attr:
portable_part = single_disk.device[:2] + "/"
if portable_part is "":
print("no portable device detected!")
os.system("pause")
exit(1)
def right_dir(location):
# 将目录统一格式为:<E:/dir/subdir/>,同时返回当前文件夹的名称
try:
right_location = location.replace("\\","/")
except:
pass
if right_location[-1] is not "/":
right_location = right_location + "/"
locs = right_location.split("/")
folder_name = locs[-2]
return folder_name,right_location
def list_all_dir(upper_dir,location):
# 返回当前目录下的所有文件夹,以子目录的形式装在全局变量dir_list中
global dir_list
temp_list = []
temp_upper = []
for item in os.listdir(location):
if os.path.splitext(item)[1] is "":
temp_item = upper_dir + item + "/"
temp_list.append(item + "/")
temp_upper.append(temp_item)
dir_list.append(temp_item)
if len(temp_list) == 0:
return
else:
for i,ti in enumerate(temp_list):
new_location = location + ti
list_all_dir(temp_upper[i],new_location)
return
def file_only_process(com_location,port_location):
'''
对于每一个目录,同步目录下的文件
1. 如果文件不是文件夹且不在“ignore”中,则进行同步
2. 如果移动设备中的文件不在电脑上,则询问删除
3. 如果电脑上的文件不在移动设备上,则进行复制
4. 如果一个文件同时在电脑和移动设备上,则比较MD5码,若不同则询问更新
'''
try:
os.mkdir(port_location)
except:
pass
port_files = os.listdir(port_location)
for item in os.listdir(com_location):
item_app = os.path.splitext(item)[1]
if item_app is not "" and item_app not in setting["ignore"]:
if item in port_files:
f_port = open(port_location+item,'rb')
f_com = open(com_location+item,'rb')
md5_port = hashlib.md5(f_port.read()).hexdigest()
md5_com = hashlib.md5(f_com.read()).hexdigest()
f_port.close()
f_com.close()
if str(md5_port) != str(md5_com):
if setting["override_updates"] is "y" or setting["override_updates"] is "Y":
shutil.copyfile(com_location+item,port_location+item)
else:
ask_update = input(port_location+item+" has been changed in the computer, update? y/n ")
if ask_update is "y" or ask_update is "Y":
shutil.copyfile(com_location+item,port_location+item)
else:
shutil.copyfile(com_location+item,port_location+item)
for item in port_files:
if item not in os.listdir(com_location):
if setting["override_delete"] is "y" or setting["override_delete"] is "Y":
os.remove(port_location+item)
else:
ask_delete = input(port_location+item+" no longer exists in the computer, delete? y/n ")
if ask_delete is "Y" or ask_delete is "y":
os.remove(port_location+item)
try:
# 检查setting.json是否可以使用,否则退出
with open("setting.json",'r') as f:
# 检查是否指定了移动设备上的同步文件夹,若没有则默认创建
# 检查指定的同步文件夹是否有效
setting = json.load(f)
if setting["portable_device_folder"] is "":
print("No folder on the portable device is assigned")
print("creating a sync folder {}sync/ in the portable device by default...".format(portable_part))
sync_folder = portable_part+"sync/"
try:
os.mkdir(sync_folder)
except:
print("sync folder already exists on the portable device")
else:
sync_folder = setting["portable_device_folder"]
_,sync_folder = right_dir(sync_folder)
try:
os.mkdir(sync_folder)
except:
pass
try:
os.listdir(sync_folder)
except:
print("The folder: {} doesn't exist".format(sync_folder))
print("check the settings")
os.system("pause")
exit(1)
except:
print("setting.json required")
os.system("pause")
exit(1)
for i,location in enumerate(setting["computer_locations"]):
# 同步所有电脑上的文件夹中的文件
# 先获取所有的次级目录
print("syncing location: {} ...".format(location))
global dir_list
dir_list = [""]
try:
all_files = os.listdir(location)
except:
print("location:{} doesn't exist on the computer".format(location))
print("skipping this location...")
continue
folder_name,location = right_dir(location)
list_all_dir("",location)
portable_location = sync_folder + folder_name + "/"
try:
os.mkdir(portable_location)
except:
pass
for single_location in dir_list:
print(" syncing /{}".format(single_location))
com_location = location + single_location
port_location = portable_location + single_location
file_only_process(com_location,port_location)
os.system("pause")