1. 程式人生 > >U盤和電腦指定目錄同步,修改後可以作為幾臺服務器之間的文件同步

U盤和電腦指定目錄同步,修改後可以作為幾臺服務器之間的文件同步

and history txt fin util any record comm text

使用場景:
同步 電腦 和 U盤 的文件,文件的修改、刪除、新增,只需要運行腳本就可以同步 電腦 和 U盤 指定的文件夾中的所有文件;
電腦 和 U盤 之間同步時候以文件內容最新的為準;
從 U 盤中刪除文件,電腦的同步目錄也會自動刪除,反之相同,這裏的刪除只是將文件從同步目錄移動到:D:\PyDiskRemoedFiles
在 U 盤新增的文件,電腦的同步目錄也會自動新增,反之相同;


配置:
1、將電腦上的所有 USB 設備拔出;
2、執行腳本,該腳本會在當前用戶家目錄下生成配置文件:Udisk_Backup.txt
修改哦欸之文件,在配置文件中需要指定電腦的同步目錄和U盤的同步目錄
3、在 U盤 主目錄下放入一個文件名為 py_udisk_identify.txt 的空文件;

備註:
1、不可以將整個電腦盤或整個 U盤 作為同步目錄,需要新建一個文件夾來指定作為同步目錄;
2、一旦執行在指定的同步目錄下會生成一個文件:SyncCompareFile ,這個文件請不要隨意刪除;
3、如果遇到程序報錯,請刪除電腦和U盤同步目錄下的 SyncCompareFile 後再次執行腳本;
4、該腳本不會自動刪除空的文件夾;
5、如果是自己在 U盤 或者 電腦對應的備份目錄下刪除的文件會被自動保存到:D:\PyDiskRemoedFiles

================================================================================================================================================================

#coding:utf-8
import os
import filecmp
import time
import datetime
import string
import pickle
import copy
import shutil
import re

#this script is use for windows files and USBdisk files synchronization
#2017年10月5日00:28:57
#author : allen

#Describe ::
#when the first use this script, you should remove all usb disk device , run the script to create config file
#config file in current user home directory ".Udisk_Backup" , this file saved computer all disk nodes name

# 使用場景:
# 同步 電腦 和 U盤 的文件,文件的修改、刪除、新增,只需要運行腳本就可以同步 電腦 和 U盤 指定的文件夾中的所有文件;
# 電腦 和 U盤 之間文件內容以最新的為準;
#
#
# 配置:
# 1、將電腦上的所有 USB 設備拔出;
# 2、執行腳本,該腳本會在當前用戶家目錄下生成配置文件:Udisk_Backup.txt
# 修改哦欸之文件,在配置文件中需要指定電腦的同步目錄和U盤的同步目錄
# 3、在 U盤 主目錄下放入一個文件名為 py_udisk_identify.txt 的空文件;
#
# 備註:
# 1、不可以將整個電腦盤或整個 U盤 作為同步目錄,需要新建一個文件夾來指定作為同步目錄;
# 2、一旦執行在指定的同步目錄下會生成一個文件:SyncCompareFile ,這個文件請不要隨意刪除;
# 3、如果遇到程序報錯,請刪除電腦和U盤同步目錄下的 SyncCompareFile 後再次執行腳本;
# 4、該腳本不會自動刪除空的文件夾;

#global variable
ComputerConfFileName = None #in user home directory config file name "Udisk_Backup.txt"
UsbConfFileName = ‘py_udisk_identify.txt‘ #identify effective usb device config file name
ComputerSyncFolderKey = ‘ComputerSyncFolderKey‘ #home directory config file assign computer sync dir path
UsbSyncFolderKey = ‘UsbSyncFolderKey‘ #home directory config file assign usb device sync dir path
SyncCompareFile = ‘SyncCompareFile‘ #in each device directory saved the device files info
BackupDir = os.path.join(‘D:‘, ‘PyDiskRemoedFiles‘)


#get path files list
def get_dir_list(path, ig_files=None):
files = os.listdir(path)
if ig_files:
for e_ig in ig_files:
if e_ig in files:
files.pop(files.index(e_ig))
files = [os.path.join(path, f) for f in files]
if_dir = [os.path.isdir(f) for f in files]
return files, if_dir

#move file to backup
def move_file(src):
global BackupDir
date = datetime.datetime.now()
time_stamp = ‘(%s_%s_%s_%s_%s)‘ % (date.year, date.month, date.day, date.hour, date.minute)
sub_dir = ‘%s_%s_%s‘ % (date.year, date.month, date.day)
path = os.path.join(BackupDir, sub_dir)
base_n = os.path.basename(src)
if not os.path.exists(path):
os.makedirs(path)
f_n = os.path.splitext(base_n)
f_n = "%s_%s_%s" % (f_n[0], time_stamp, f_n[-1])
f_n = os.path.join(path, f_n)
shutil.move(src, f_n)


#get computer current disk nodes
def get_disks_info():
ident_str = string.ascii_uppercase
primary_nodes = []
for node in ident_str:
try:
node = ‘%s:‘ % node
os.stat(node)
primary_nodes.append(node)
except (FileNotFoundError, PermissionError) as e:
pass
return primary_nodes


#copy the file from path_1 to path_2
def copy_file(org_path, targ_p):
targ_p_d = os.path.dirname(targ_p)
if not os.path.exists(targ_p_d):
os.makedirs(targ_p_d)
try:
shutil.copy(org_path, targ_p)
except PermissionError:
print(‘同步的文件已經被打開,請關閉文件後再次執行該腳本‘)
time.sleep(100)



#compare two files if common and the newest will cover the old one
def compare_file(f_1, f_2):
try:
if not filecmp.cmp(f_1, f_2):
f_1_mt = os.stat(f_1).st_mtime
f_2_mt = os.stat(f_2).st_mtime
if f_1_mt > f_2_mt:
os.remove(f_2)
shutil.copy(f_1, f_2)
elif f_1_mt < f_2_mt:
os.remove(f_1)
shutil.copy(f_2, f_1)
except FileNotFoundError:
pass


#get set meta data
def get_set_d(key_s, list_1, list_2):
key_s = key_s.replace(‘\\‘, ‘/‘)
list_1.extend(list_2)
list_d = ‘?‘.join(list_1)
list_d = list_d.replace(‘\\‘, ‘/‘)
p_str = r‘[^?]*?%s‘ % key_s
pattern = re.compile(p_str)
res = pattern.findall(list_d)
return res[0].replace(‘/‘, ‘\\‘)




#replace the set data assign char generate new char
def replace_set(set_data, old, new):
result = set()
while True:
try:
each = set_data.pop()
result.add(each.replace(old, new))
except KeyError:
break
return result


#use pickle save dict data
def save_files_info(f_n, in_d, key):
"""
:param f_n: file name
:param in_d: input data
:param key: history_all_files, current_files
:return:
"""
in_d = set(in_d)
old_cur_d = None
if os.path.exists(f_n):
with open(f_n, ‘rb‘) as fp:
all_d = pickle.load(fp)
f_d = all_d.get(key, set())
if key == ‘history_all_files‘:
dif_d = in_d - f_d
f_d.update(dif_d)
all_d[key] = f_d
else:
old_cur_d = all_d.get(key, set())
all_d[key] = in_d
with open(f_n, ‘wb‘) as fp:
pickle.dump(all_d, fp)
return old_cur_d
else:
with open(f_n, ‘wb‘) as fp:
pickle.dump({key: in_d}, fp)



#read pickle file, the file content is a dict
def read_pickle(f_n, key):
try:
with open(f_n, ‘rb‘) as fp:
data = pickle.load(fp)
data = data.get(key, set())
return data
except FileNotFoundError:
return set()

#make directorys
def mk_dirs(p):
if not os.path.exists(p):
os.makedirs(p)

#recursion assign path get all files list
class BaseClass(object):
def __init__(self):
self.all_files = []

def get_all_files(self, path, ig_files=None):
files, if_dir = get_dir_list(path, ig_files)
while any(if_dir):
for index, judge in enumerate(if_dir):
if_dir.pop(index)
f = files.pop(index)
if not judge:
self.all_files.append(f)
else:
self.get_all_files(f)
else:
self.all_files.extend(files)


#create init conf file in current user home dir
class InitConfig(object):
def __init__(self):
self.home_path = os.path.join(‘C:‘, os.environ[‘HOMEPATH‘]) #get current user home dir
self.primary_disks = self.local_d_record() #get computer primary folders

def local_d_record(self):
global ComputerConfFileName, ComputerSyncFolderKey, UsbSyncFolderKey
conf_n = os.path.join(self.home_path, ‘%s.txt‘ % os.path.basename(__file__).split(‘.‘)[0])
ComputerConfFileName = conf_n
if not os.path.exists(conf_n):
primary_nodes = get_disks_info()
with open(conf_n, ‘w‘) as fp:
fp.write(‘%s\n\n#在等號後面填寫自己的電腦的同步的文件夾,不能指定某個盤作為同步,一定需要同步文件夾\n%s=\n\n#在等號後面填寫自己的U盤文件夾,不能指定整個 U盤,可以指定某個文件夾作為同步\n%s=‘ % (str(primary_nodes), ComputerSyncFolderKey, UsbSyncFolderKey))
return primary_nodes
else:
with open(conf_n, ‘r‘) as fp:
try:
primary_nodes = eval(fp.readline().replace(‘ ‘, ‘‘))
return primary_nodes
except SyntaxError:
print(‘請手動刪除該文件後再次執行腳本 :: %s‘ % ComputerConfFileName)



class SyncDir(BaseClass):
def __init__(self):
super().__init__()
self.m_stor_dev = self.get_usb_driver() #get config file portable storage device lists
self.main()


#get all can use storage device, this step include identify effective usb device
def get_usb_driver(self):
usb_devices = []
try:
usb_disk = set(get_disks_info()) - set(InitConfig().primary_disks) # get usb disk driver letter
if not usb_disk:
print(‘請按照以下步驟配置:\n1、把這個文件刪除(如果沒有就不用刪除) :%s‘ % ComputerConfFileName)
print(‘2、把掉電腦上的所有 U 盤拔掉後再次執行腳本並修改該文件指定電腦和 U 盤目錄:%s‘ % ComputerConfFileName)
print(‘3、在你需要使用的 U盤 中放入一個文件名為 “py_udisk_identify.txt” 的文件,該文件用於識別需要同步的 U盤‘)
return False
else:
while True:
try:
usb_id = usb_disk.pop()
usb_id_f = os.path.join(usb_id, UsbConfFileName)
if os.path.exists(usb_id_f):
usb_devices.append(usb_id)
else:
print(‘沒能找到文件 :%s\n所以認為 %s 盤 不是用來同步的移動存儲設備,如果需要使用該設備同步請在該設備下放入一個文件名為的空文件 :%s‘ % (usb_id_f, usb_id, UsbConfFileName))
except KeyError:
return usb_devices
except TypeError:
pass

#read user directory config file
def get_conf_info(self):
global ComputerConfFileName
result = {}
with open(ComputerConfFileName, ‘r‘) as fp:
data = fp.read()
data = [d for d in data.split(‘\n‘) if ‘=‘ in d]
for i in data:
c = i.split(‘=‘)
result[c[0]] = c[1].replace(‘ ‘, ‘‘)
return result

#get computer and usb storage dir
def get_device_dir(self):
_dir = self.get_conf_info()
com_dir = _dir[‘ComputerSyncFolderKey‘]
if not _dir[‘UsbSyncFolderKey‘]:
usb_dir = self.get_usb_driver()
else:
usb_dir = [os.path.join(dr, _dir[‘UsbSyncFolderKey‘]) for dr in self.get_usb_driver()]
return com_dir, usb_dir

#according computer and usb assgin directory build all files info
def main(self):
global SyncCompareFile
com_dir, usb_dir = self.get_device_dir()
usb_dir_bak = copy.deepcopy(usb_dir)
usb_dir.append(com_dir)
old_cur_data = {}
for each_dir in usb_dir:
f_n = os.path.join(each_dir, SyncCompareFile)
mk_dirs(each_dir)
self.get_all_files(each_dir, ig_files=[SyncCompareFile,])
save_files_info(f_n=f_n, in_d=self.all_files, key=‘history_all_files‘)
old_cur_d = save_files_info(f_n=f_n, in_d=self.all_files, key=‘current_files‘)
old_cur_data[each_dir] = old_cur_d
self.all_files = []
com_files = read_pickle(os.path.join(com_dir, SyncCompareFile), key=‘current_files‘)
com_files_bak = copy.deepcopy(com_files)
com_files_pure = replace_set(com_files_bak, com_dir + os.sep, ‘‘)
for u_dir in usb_dir_bak:
u_files = read_pickle(os.path.join(u_dir, SyncCompareFile), key=‘current_files‘)
u_del_files = old_cur_data.get(u_dir, set()) - u_files #deleted computer files
u_del_files_bak = copy.deepcopy(u_del_files)
u_del_files_pure = replace_set(u_del_files_bak, u_dir + os.sep, ‘‘)

c_del_files = old_cur_data.get(com_dir, set()) - com_files #delted usb files
c_del_files_bak = copy.deepcopy(c_del_files)
c_del_files_pure = replace_set(c_del_files_bak, com_dir + os.sep, ‘‘)
u_files_bak = copy.deepcopy(u_files)
u_files_pure = replace_set(u_files_bak, u_dir + os.sep, ‘‘)
diff_f = com_files_pure ^ u_files_pure # difference set

#delete computer file
while True:
try:
e_u_del_file = u_del_files_pure.pop()
f_n = os.path.join(com_dir, e_u_del_file)
try:
move_file(f_n)
except FileNotFoundError:
pass
diff_f.remove(e_u_del_file)
except KeyError:
break

#delete usb file
while True:
try:
e_c_del_file = c_del_files_pure.pop()
f_n = os.path.join(u_dir, e_c_del_file)
try:
move_file(f_n)
except FileNotFoundError:
pass
diff_f.remove(e_c_del_file)
except KeyError:
break

#process new add file
while True:
try:
e_dif_d = diff_f.pop()
abs_c_f_diff = os.path.join(com_dir, e_dif_d)
abs_u_f_diff = os.path.join(u_dir, e_dif_d)
if not os.path.exists(abs_c_f_diff):
copy_file(org_path=abs_u_f_diff, targ_p=abs_c_f_diff)
elif not os.path.exists(abs_u_f_diff):
copy_file(org_path=abs_c_f_diff, targ_p=abs_u_f_diff)
except KeyError:
break

#compare exists file and new will cover olders
comm_set = com_files_pure & u_files_pure
while True:
try:
e_com_d = comm_set.pop()
abs_c_f_com = os.path.join(com_dir, e_com_d)
abs_u_f_com = os.path.join(u_dir, e_com_d)
compare_file(abs_c_f_com, abs_u_f_com)
except KeyError:
break




if __name__ == ‘__main__‘:
print(‘=‘*78)
print(‘==如果看到提示信息,請按照提示信息操作後,並關閉這個命令窗口然後再次雙擊執行==‘)
print(‘=‘*78)

try:
SyncDir()
except Exception:
print(‘程序運行出現了錯誤,很可能是因為 SyncCompareFile 這個文件被刪除,請不要刪除這個文件\n現在再次執行就可以了‘)
time.sleep(100)
print(‘程序執行完成!‘)
time.sleep(100)

U盤和電腦指定目錄同步,修改後可以作為幾臺服務器之間的文件同步