如何解决比较两个文件名列表+大小+修改时间
对于一个学生项目,我构建了一个脚本来仅将“新”文件复制到远程库。 我能够找到远程文件夹中不存在的文件并复制它,它正在工作。 现在,我尝试复制具有相同名称但具有不同大小或修改日期的文件。
localfilestime = os.scandir(_SOURCE)
print("fichiers sur répertoire source: \n ")
for file in localfilestime:
localfilestime = (file.stat().st_size,file.stat().st_mtime,file.name)
print (localfilestime)
远方的也一样:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy( paramiko.AutoAddPolicy() )
ssh.connect(_RMTHOST,username=_USR,password=_DESTPASS)
ftp = ssh.open_sftp()
distfilestime = ftp.listdir_attr(_DEST)
print("fichiers sur répertoire de destination: \n")
for f in distfilestime:
distfilestime =(f.st_size,f.st_mtime,f.filename)
print (distfilestime)
我得到两个排序列表,但我有两个问题:
fichiers sur répertoire source:
(915,1622736305.82416,'20_060_12C_24T_3800_AMD_Ryzen_9_3900X_12_Core_Processor_64_Bit.txt')
(9602,1624743218.308332,'blabla.txt')
(143897,1583941480.0,'Projet4_configuration_navigateur_proxy01.jpg')
(0,1624520128.9788647,'testcopie.txt')
**********************************************************************************************************
fichiers sur répertoire de destination:
(915,1622736305,'20_060_12C_24T_3800_AMD_Ryzen_9_3900X_12_Core_Processor_64_Bit.txt')
(37,1624738406,1583941480,1624520128,'testcopie.txt')
-
本地列表中的 mtime 返回一个浮点数,而不是远处的,我认为无法正确比较这些数字。
-
我找不到一个可行的解决方案来比较这些文件列表,我尝试了很多解决方案,但“不那么糟糕”:
def get_difference(list_a,list_b): return set(list_a) - set(list_b) list_a = localfilestime list_b = distfilestime non_match = list(get_difference(list_a,list_b)) print("No match elements: ",set(non_match))
只返回一个未修改的文件 mtime,而不是像 "blabla.txt" 这样不同大小的文件:
No match elements: {1624520128.9788647}
我确定我在某个地方犯了错误,也许我的方法不好。有人可以帮我解答这个问题吗?
编辑:这是整个脚本,在 2 个局域网服务器之间的 Win10 上使用 (1 个物理,1 个在私有共享网络上的 VirtualBox)脚本调用配置文件。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import socket
import paramiko
import pysftp
import shutil
# importation des variables globales
from configuration import _USR,_RMTHOST,_DESTPASS,_PORT,_SOURCE,_DEST,_EXCLUSION,_TIMEDATE,_OUTPUT
#DéFinition de la variable globale nécessaire à la création du dussier temporaire de copie
_SOURCE_TEMP = (_SOURCE + "temp")
#effacer dossier temporaire en cas d'erreur du script précédent
if os.path.exists(_SOURCE_TEMP):
shutil.rmtree(_SOURCE_TEMP)
# énoncé du script
print("\ncopie miroir du dossier: " + _SOURCE + " vers:" + _RMTHOST +(": ") + _DEST)
print("\n**********************************************************************************************************\n")
# vérifier présence du fichier de configuration
try:
with open('configuration.py'):
pass
print("le fichier de configuration est présent et valide")
except IOError:
sys.exit("Erreur: le fichier de configuration n’est pas present,annulation du backup")
print("\n**********************************************************************************************************\n")
# Vérifier l'accès au fichier source
if os.path.exists(_SOURCE):
print("le dossier source: ","est valide et accessible \n \n")
else:
print("le dossier source: ","n\’est pas valide/existant,annulation du backup \n \n")
sys.exit()
print("**********************************************************************************************************\n")
# test de connexion vers le serveur distant
with socket.socket(socket.AF_INET,socket.soCK_STREAM) as s:
try:
s.connect((_RMTHOST,_PORT))
s.sendall(b'Hello,world')
data = s.recv(1024)
print('communication réussie avec le serveur ' + _RMTHOST,repr(data) + ('\n \n'))
except Exception as ex:
print(
"impossible de se connecter au serveur,vérifiez vos identifiants\n \n************************ \n\nannulation de la sauvegarde")
sys.exit()
print("**********************************************************************************************************\n")
# création de liste de fichiers locaux
localfilestime = os.scandir(_SOURCE)
print("fichiers sur répertoire source: \n ")
for f in localfilestime:
localfilestime = (f.stat().st_size,f.stat().st_mtime,f.name)
print (localfilestime)
print("**********************************************************************************************************\n")
#connexion pour listing fichiers présents répertoire distant
ssh = paramiko.SSHClient()
# importation auto de clé de connexion avec le client
ssh.set_missing_host_key_policy( paramiko.AutoAddPolicy())
ssh.connect(_RMTHOST,password=_DESTPASS)
ftp = ssh.open_sftp()
distfilestime = ftp.listdir_attr(_DEST)
print("fichiers sur répertoire de destination: \n")
for f in distfilestime:
distfilestime =(f.st_size,f.filename)
print (distfilestime)
#comparaison éléments
loc_files = {}
for f in localfilestime:
size = f.stat().st_size
time = int(f.stat().st_mtime)
name = f.name
loc_files[(size,time,name)] = f
srv_files = {}
for f in distfilestime:
size = f.st_size
time = f.st_mtime
name = f.filename
srv_files[(size,name)] = f
# get lists of unique files based on keys (size,name) of these dicts
loc_uniq = [ loc_files[x] for x in loc_files if x not in srv_files ]
srv_uniq = [ srv_files[x] for x in srv_files if x not in loc_files ]
print(loc_uniq)
print("\n**********************************************************************************************************\n")
# création du répertoire temporaire pour copie
_SOURCE_TEMP = (_SOURCE + "temp")
if not os.path.exists(_SOURCE_TEMP):
os.makedirs(_SOURCE_TEMP,exist_ok=True)
#clôture de la connexion avec le serveur distant
ssh.close()
ftp.close()
#copie des fichiers absents du répertoire distant sur le dossier temporaire pour transfert
os.chdir(_SOURCE)
for files in loc_uniq:
shutil.copy2(files,_SOURCE_TEMP)
#retirer fichiers à exclure
os.chdir(_SOURCE_TEMP)
files = [f for f in os.listdir('.') if os.path.isfile(f)]
for f in files:
if f.endswith(_EXCLUSION):
print(f,"ne sera pas copié selon la liste d'exclusion")
os.remove(f)
os.chdir(_SOURCE)
print("\n**********************************************************************************************************\n")
#copie des fichiers dans le répertoire distant
with pysftp.Connection(host=_RMTHOST,password=_DESTPASS) as sftp:
sftp.put(_SOURCE_TEMP,preserve_mtime=True)
sftp.close()
if os.path.exists(_SOURCE_TEMP):
shutil.rmtree(_SOURCE_TEMP)
配置文件:
import time
_EXCLUSION = '.ini'
_SOURCE = "C:\\Users\\XXX\\testp6\\"
_OUTPUT = _SOURCE + time.strftime('%Y_%m_%d-%Hh%Mmin%ss')
_TIMEDATE = time.strftime('%Y_%m_%d-%Hh%Mmin%ss')
_DEST = "C:\\Users\\XXXx\\test_distant_p6\\"
_USR = 'XXX'
_RMTHOST ='192.168.56.103'
_DESTPASS='XXX'
_PORT=22
和实际回报:
copie miroir du dossier: C:\Users\Jerem\testp6\ vers:192.168.56.103: C:\Users\turmix\test_distant_p6\
**********************************************************************************************************
le fichier de configuration est présent et valide
**********************************************************************************************************
le dossier source: C:\Users\Jerem\testp6\ est valide et accessible
**********************************************************************************************************
communication réussie avec le serveur 192.168.56.103 b'SSH-2.0-OpenSSH_for_Windows_8.1\r\n'
**********************************************************************************************************
fichiers sur répertoire source:
(915,'blabla.txt')
(46,1624736892.7385924,'desktop.ini')
(143897,'Projet4_Jeremie_Voita_configuration_navigateur_proxy01.jpg')
(0,'testcopie.txt')
Traceback (most recent call last):
File "C:\Users\jerem\OneDrive\P6\pythonP6\dernierendate.py",line 118,in <module>
size = f.stat().st_size
AttributeError: 'int' object has no attribute 'stat'
Process finished with exit code 1
解决方法
它可以通过多种方式完成。例如这种方式:
localfilestime = [
(915,1622736305.82416,'20_060_12C_24T_3800_AMD_Ryzen_9_3900X_12_Core_Processor_64_Bit.txt'),(9602,1624743218.308332,'blabla.txt'),(143897,1583941480.0,'Projet4_configuration_navigateur_proxy01.jpg'),(0,1624520128.9788647,'testcopie.txt'),]
distfilestime = [
(915,1622736305,(37,1624738406,1583941480,1624520128,]
# convert float dates into integer dates
localfilestime = [(size,int(date),name) for (size,date,name) in localfilestime]
# convert every element of the lists into a { key:value }
localfilestime = { str(x):x for x in localfilestime }
distfilestime = { str(x):x for x in distfilestime }
# get unique values from the lists
localfilestime_uniques = { localfilestime[x] for x in localfilestime if x not in distfilestime }
distfilestime_uniques = { distfilestime[x] for x in distfilestime if x not in localfilestime }
print(localfilestime_uniques) # {(9602,1624743218,'blabla.txt')}
print(distfilestime_uniques) # {(37,'blabla.txt')}
更新
可能你需要这个:
# make the dicts { (size,time,name) : file }
loc_files = {}
for f in localfilestime:
size = f.stat().st_size
time = int(f.stat().st_mtime)
name = f.name
loc_files[(size,name)] = f
srv_files = {}
for f in distfilestime:
size = f.st_size
time = f.st_mtime
name = f.filename
srv_files[(size,name)] = f
# get lists of unique files based on keys (size,name) of these dicts
loc_uniq = [ loc_files[x] for x in loc_files if x not in srv_files ]
srv_uniq = [ srv_files[x] for x in srv_files if x not in loc_files ]
理论上它应该可以工作,它应该为您提供两个具有唯一文件的列表(基于大小、时间、名称)。但是我无法正确测试它,因为我没有包含您文件的 FTP 服务器。
我已经在 Windows 和 Mac 上测试了代码的本地部分,这部分工作得很好:
import os
from pprint import pprint
localfilestime = os.scandir(r"c:\\temp")
loc_files = {}
for f in localfilestime:
size = f.stat().st_size
time = int(f.stat().st_mtime)
name = f.name
loc_files[(size,name)] = f
pprint(loc_files)
输出示例:
{(0,1622330493,'test - Copy.txt'): <DirEntry 'test - Copy.txt'>,'test.txt'): <DirEntry 'test.txt'>,(124,1622332489,'test.zip'): <DirEntry 'test.zip'>,(267,1624901883,'loc_files.py'): <DirEntry 'loc_files.py'>}
,
感谢@Yuri Khristich,我有一个完美的解决方案:
使用:
import os
import sys
import socket
import paramiko
import pysftp
import shutil
from pprint import pprint
#for local files
localfilestime = os.scandir(r"c:\\temp")
loc_files = {}
for f in localfilestime:
size = f.stat().st_size
time = int(f.stat().st_mtime)
name = f.name
loc_files[(size,name)] = f
print("fichiers sur répertoire source: \n ")
pprint(loc_files)
#for distant files
ssh = paramiko.SSHClient()
# importation auto de clé de connexion avec le client
ssh.set_missing_host_key_policy( paramiko.AutoAddPolicy())
ssh.connect(_RMTHOST,username=_USR,password=_DESTPASS)
ftp = ssh.open_sftp()
distfilestime = ftp.listdir_attr(_DEST)
dst_files = {}
for f in distfilestime:
size = f.st_size
time = f.st_mtime
name = f.filename
dst_files[(size,name)] = f
print("fichiers sur répertoire de destination: \n")
pprint(dst_files)
#clôture de la connexion avec le serveur distant
ssh.close()
ftp.close()
#create a list of files not present/differents(name,size,modification date) on the distant server:
loc_uniq = [ loc_files[x] for x in loc_files if x not in dst_files ]
#create a temp folder to copy the different files
_SOURCE_TEMP = (_SOURCE + "temp")
if not os.path.exists(_SOURCE_TEMP):
os.makedirs(_SOURCE_TEMP,exist_ok=True)
#copy the files
for files in loc_uniq:
shutil.copy2(files,_SOURCE_TEMP)
#if you want to exclude some files from the copy list
os.chdir(_SOURCE_TEMP)
files = [f for f in os.listdir('.') if os.path.isfile(f)]
for f in files:
if f.endswith(_EXCLUSION):
print(f,"ne sera pas copié selon la liste d'exclusion")
os.remove(f)
#copy the files from the temp repertory to the distant
with pysftp.Connection(host=_RMTHOST,password=_DESTPASS) as sftp:
sftp.put_r(_SOURCE_TEMP,_DEST,preserve_mtime=True)
sftp.close()
这部分脚本在 Win10 上完美运行,列表也在 OSX 上运行(由 Yuri 测试)我第一次遇到错误(在 size = f.stat().st_size,AttributeError: 'int' object has没有属性 'stat') 因为我导入了“时间”模块,请注意这一点。 感谢您 1000 次对 Yuri 的帮助!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。