# -*- coding: utf-8 -*- import string import os import sys import zlib import zipfile import time,calendar import binascii import struct chaineretour='' GlobalPVersion='2.04' def vprint(txt): global chaineretour if __name__ == '__main__': print(txt) else: chaineretour+=txt+'\n' def aide(num='1'): if num=='0': print """ MMcc ccMM M cccccccc M M cccccccc M M ccM Mcc M M Mc M M Mc M M cMc M M M M M Mc M M M M M M MccccccM Mcccccc M M M M M M M M M M M M Mc M M Mc M M M M cccccccc M M cccccccc Mcccc ccccc c c c c ccccc c c c cMc c M McM M M cMc c McM M M cc M M Mc M M cM M Mc M M M M M M M M M M M M M M M cMcccccMc cc M Mcccccc cMcccccMc M M cc M M M cM M cc M M M M cMc c M M M ccM cMc c M M cc cc ccccc ccccc c c c ccccc c c ccc http://mclaveau.com """ if num=='1': print """ J'étais certain que vous auriez besoin d'aide ! Bon puisque ce moment est arrivé, voici quelques tuyaux (ne vous attendez pas à des miracles) : Il faut taper quelque chose comme : zipmci.py commande fichier-zip fichiers-ou-patterns 'commande' pouvant être, au choix : -TT test global -T test par fichiers, avec recherche du premier fichier non valide -L liste (triée) des fichiers archivés, sur 2 colonnes -V liste (triée) des fichiers archivés, avec date-time, tailles -PD appelle le printdir() de ZipFile.py -A ajoute (si déjà existant, ajoute une nouvelle occurence) -U 'update' c-a-d ajoute, si le fichier est manquant, ou supprime, puis ajoute, si le fichier est différent (contenu ou date/heure) -E extrait des fichiers, en (re)-affectant le date-time enregistré -D supprime des fichiers dans le fichier-zip -B sans commentaire (c'est une blague ?). -P liste les paramètres utilisés dans l'appel courant de ZipMCI.py -H x Aide (help), avec x = 0, 1, 2, 3, 4 ou 5 N'OUBLIEZ PAS l'espace après 'H' exemple : zipmci.py -H 0 """ elif num=='2': print """ ZipMCI.py est un utilitaire-exemple (d'utilisation) du module zipfile.py. Il est destiné à un usage en ligne (invite) de commande, sous Windows. SGDG, il a été testé avec Python 2.2, sous W2K & WXP. Au départ, c'était pour remplacer PkZip, qui avait quelques problèmes avec les noms longs. Qq trucs : - la commande peut être sous plusieurs formes ; par exemple : -v -V v V sont identiques. - le fichier-zip peut être cité sans l'extension exemple : Toto & Toto.zip sont identiques - lorsque les listes sont triées, il n'y a pas de casse (pas de différence majuscules/munuscules) - les "patterns" peuvent avoir différentes formes : "*.py *.jpg *.gif" & "*.py;*.jpg;*.gif" sont identiques "image.* toto.jpg toto.gif" est accepté (mais peut créer des doublons) les patterns sont gérés de façon minimale. e.g. 'ti*.py' ne marche pas. le fichier-zip courant est éliminé des listes/patterns - la suppression ('-D') utilise des fichiers temporaires, supprimés à la fin (XXXXXXXX.TMP & XXXXXXXX.ZIP ; les droits doivent être suffisants) """ elif num=='3': print """ L'aide numéro 3 n'est pas définie. C'était juste pour frimer, en faisant croire à un logiciel hyper-complet, ce que ZipMCI.py n'est pas. Tant pis pour vous (pour l'instant). """ elif num=='4': print """ Licence : --------- Le logiciel est fourni 'tel quel', sans support, ni assistance, ni garantie, d'aucune sorte. Le code-source est entièrement libre. Toutefois, il serait apprécié de citer/laisser les coordonnées du développeur : Michel Claveau Informatique http://mclaveau.com Contributions : --------------- Si vous désirez laisser une contribution volontaire, contactez-moi. Une facture sera systématiquement envoyée au contributeur. Le montant de toute contribution est libre. Cependant, il est demandé de ne pas envisager de montants inférieurs à 1 000 000 Euros (ou 1.000.000 dollars). En effet, je n'ai pas envie de m'embêter avec la petite monnaie. Prestations : ------------- Je vis des prestations informatiques. Si vous avez un besoin (et un budget), vous pouvez me contacter à mc@mclaveau.com (attention j'ai des filtres anti-spams assez 'durs' ; si vous n'avez pas de réponse, envoyez d'autres messages).""" elif num=='5': print """ Qq. trucs : ----------- Il y a des options secrètes. Par exemple '-EE', '-AA'. Il s'agit simplement d'un autre code, pour une autre façon de réaliser une fonction déjà existante (ouf !). Cela peut être un code historiquement obsolète (je n'ai malheureusement pas développé ce logiciel 'du premier coup', malgré mes désirs algorithmiquement mégalomaniaques). Ce peut aussi être la conséquence d'essais pas vraiment convainquant (malgré...) Dernier cas : cela peut résulter d'un papillonnement dû à un besoin de se changer les idées. Bref, pour tout cela, il est recommandé de parcourir le code. """ pass sys.exit(0) def formatDate(datetime): # à partir d'une liste, on présente le date-time "à l'européenne" sdtime = '%02d-%02d-%04d %02d:%02d.%02d' % (datetime[2], datetime[1], datetime[0], datetime[3], datetime[4], datetime[5]) return sdtime def filter(lst, patterns): """ Retourne deux sous-listes de la liste-fichiers LST : - la première est la liste qui respecte la liste PATTERNS - la deuxième est la liste qui ne respecte pas la liste PATTERNS filter remplace fnmatch, car sous Windows fnmatch se plante avec '*.*' et les fichiers '*.' """ result=[] antiresult=[] for pattern in patterns: patroot,patext=os.path.splitext(pattern) patroot=string.upper(patroot) patext=string.upper(patext) for item in lst: tmproot,tmpext=os.path.splitext(item) tmproot=string.upper(tmproot) tmpext=string.upper(tmpext) if (tmproot==patroot or patroot=="*") and (tmpext==patext or patext==".*") : result.append(item) for item in lst: if not item in result: antiresult.append(item) result.sort() antiresult.sort() return(result,antiresult) def zipddelete(fichierzip,patterns): """ Ancienne méthode (la première testée, en fait) ; remplacée par '-D' Ici, pour chaque fichier conservé, on le crée sur disque, puis on le recompresse dans le nouveau fichier-zip. A la fin, on supprime l'ancien fichier-zip, et on renomme le nouveau. """ global chaineretour chaineretour='' try: z=zipfile.ZipFile(fichierzip,"r") z2=zipfile.ZipFile("XXXXXXXX.ZIP","w") lst,antilst=filter(z.namelist(),patterns) for i in antilst: print i, bytes = z.read(i) f = open("XXXXXXXX.TMP", "wb") f.write(bytes) f.close() info=z.getinfo(i) # on récupère le date-time du fichier, pour ré-affecter la bonne valeur ltmp=list(info.date_time) ltmp.append(0) ltmp.append(0) ltmp.append(0) ltmp[3]=ltmp[3]+(time.timezone/3600) #correction du GMT-TimeZone (France only ?) filtime=time.mktime(ltmp) os.utime("XXXXXXXX.TMP",(filtime,filtime)) # (re)-affectation du date-time archivé z2.write("XXXXXXXX.TMP",i,zipfile.ZIP_DEFLATED) print 'recorded' z.close() z2.close() print"Delete :",lst os.remove("XXXXXXXX.TMP") os.remove(fichierzip) os.rename("XXXXXXXX.ZIP",fichierzip) flag='OK' except: flag='Erreur' vprint(flag) def zipdelete(fichierzip,patterns): """ Utilisation du fichier temporaire XXXXXXXX.ZIP (renommé/remplace, à la fin pour re-obtenir le fichier-zip) Principe : on ouvre un nouveau fichier-zip ; puis on copie, un par un les fichiers conservés. Pour gagner en performances, j'avais 2 possibilités : - mettre un Pentium à 8 ou 12 GHz ; - traiter directement les fichiers compressés (méthode retenue) Donc, pour chaque fichier conservé, on lit sa version compressée, puis on l'écrit dans le 2eme fichier-zip, tel quel, sans utiliser de décompression/recompression. Cela est beaucoup plus rapide ; inconvénient : il faut que le fichier tienne en RAM. """ global chaineretour chaineretour='' try: z=zipfile.ZipFile(fichierzip,"r") z2=zipfile.ZipFile("XXXXXXXX.ZIP","w") lst,antilst=filter(z.namelist(),patterns) #lst contient la liste à supprimer ; antilst la liste à garder for item in antilst: #print item, zinfo = z.getinfo(item) zinf2 = zipfile.ZipInfo(zinfo.filename, zinfo.date_time) zinf2.CRC = zinfo.CRC zinf2.compress_size = zinfo.compress_size zinf2.file_size = zinfo.file_size zinf2.date_time = zinfo.date_time zinf2.filename = zinfo.filename zinf2.external_attr = zinfo.external_attr zinf2.compress_type = zinfo.compress_type filepos = z.fp.tell() z.fp.seek(zinfo.file_offset, 0) bytes = z.fp.read(zinfo.compress_size) z2._writecheck(zinf2) zinf2.flag_bits = 0x00 zinf2.header_offset = z2.fp.tell() # Start of header bytes z2.fp.write(zinf2.FileHeader()) zinf2.file_offset = z2.fp.tell() # Start of file bytes z2.fp.write(bytes) position = z2.fp.tell() # Preserve current position in file z2.fp.seek(zinf2.header_offset + 14, 0) z2.fp.write(struct.pack("2: todelete.append(i) toadd.append(i) vprint(i+"Dates/heures diff."+time.strftime('%d.%m.%y %H:%M:%S',time.localtime(statf[8]))+"&"+time.strftime('%d.%m.%y %H:%M:%S',time.gmtime(filtime))) else: pass #*** """ #*** try: f = open(i, "rb") bbytes=f.read() f.close() except: vprint(i+"Pb d'acces au fichier.") try: todelete.append(i) toadd.append(i) print "Maj",i,"forcee." except: print"Pb DUR avec",i else: if bbytes!=bytes: todelete.append(i) toadd.append(i) vprint(i+" Contenu different.") """ except: vprint("Error not determined.") flag="Ok" z.close() if len(todelete)>0: #print "-"*50,"a supprimer" #print todelete zipdelete(fichierzip,todelete) if len(toadd)>0: #print "="*50,"a ajouter" #print toadd zipappend(fichierzip,toadd) except: print"Erreur ! "*7 #time.sleep(3) flag='Erreur' def zipcompar(fichierzip,patterns=[''],lstfichiers=[]): global chaineretour chaineretour='' vprint("Debut de comparaison") try: z=zipfile.ZipFile(fichierzip,"r") zl = z.infolist() zlst=[] for item in zl: #zlst.append(item.filename) zlst.append(item.filename.upper()) if lstfichiers==[]: # on collecte les fichiers du répertoire courant for i in os.listdir(os.getcwd()): if not os.path.isdir(i): lstfichiers.append(i) if patterns==['']: lst=lstfichiers antilst=[] else: lst,antilst=filter(lstfichiers,patterns) ldiff=[] for i in lst: if fichierzip.upper()==i.upper(): loop if i.upper() not in zlst: ldiff.append([i,'manque']) vprint(i+' manque dans le zip') else: info=z.getinfo(i) filtime=calendar.timegm(info.date_time) #bytes = z.read(i) #*** try: statf=os.stat(i) if abs(calendar.timegm(time.localtime(statf[8]))-filtime)>242: ldiff.append([i,'Dates/heures diff.: '+time.strftime('%d.%m.%y %H:%M:%S',time.localtime(statf[8]))+" & "+time.strftime('%d.%m.%y %H:%M:%S',time.gmtime(filtime))]) else: pass #*** """ #*** try: f = open(i, "rb") bbytes=f.read() f.close() except: vprint(i+"Pb d'acces au fichier.") try: ldiff([i,'Pb d'accès ; Maj forcee.']) except: print"Pb DUR avec",i else: if bbytes!=bytes: ldiff([i,'Content different.']) """ except: vprint("Error not determined.") flag="Ok" z.close() print"Differences" for i in ldiff: vprint(i) except: flag='Erreur' def zipextract(fichierzip,patterns): global chaineretour chaineretour='' try: z=zipfile.ZipFile(fichierzip,"r") lst,antilst=filter(z.namelist(),patterns) for i in lst: info=z.getinfo(i) print str(info.file_size).rjust(8)," ",formatDate(info.date_time)," ",i # on récupère le date-time du fichier, pour ré-affecter la bonne valeur ltmp=list(info.date_time) ltmp.append(0) ltmp.append(0) ltmp.append(0) ltmp[3]=ltmp[3]+(time.timezone/3600) #correction du GMT-TimeZone (France only ?) filtime=time.mktime(ltmp) bytes = z.read(i) f = open(i, "wb") f.write(bytes) f.close() os.utime(i,(filtime,filtime)) # (re)-affectation du date-time archivé flag="Ok" z.close() except: flag='Erreur' vprint(flag) def zipeextract(fichierzip,patterns): global chaineretour chaineretour='' try: z=zipfile.ZipFile(fichierzip,"r") lst,antilst=filter(z.namelist(),patterns) for fichier in lst: zinfo = z.getinfo(fichier) filepos = z.fp.tell() z.fp.seek(zinfo.file_offset, 0) bytes = z.fp.read(zinfo.compress_size) # maintenant, 'bytes' contient l'objet (=fichier) compressé z.fp.seek(filepos, 0) if zinfo.compress_type == zipfile.ZIP_STORED: pass elif zinfo.compress_type == zipfile.ZIP_DEFLATED: dc = zlib.decompressobj(-15) bytes = dc.decompress(bytes) ex = dc.decompress('Z') + dc.flush() if ex: bytes = bytes + ex else: raise BadZipfile, "Unsupported compression method %d for file %s" % (zinfo.compress_type, name) crc = binascii.crc32(bytes) if crc != zinfo.CRC: raise BadZipfile, "Bad CRC-32 for file %s" % name print str(zinfo.file_size).rjust(8)," ",formatDate(zinfo.date_time)," ",fichier # on récupère le date-time du fichier, pour ré-affecter la bonne valeur ltmp=list(zinfo.date_time) ltmp.append(0) ltmp.append(0) ltmp.append(0) ltmp[3]=ltmp[3]+(time.timezone/3600) #correction du GMT-TimeZone (France only ?) filtime=time.mktime(ltmp) f = open(fichier, "wb") f.write(bytes) f.close() os.utime(fichier,(filtime,filtime)) # (re)-affectation du date-time archivé flag="Ok" z.close() except: flag='Erreur' vprint(flag) def ziplist(fichierzip): global chaineretour chaineretour='' try: lst=zipfile.ZipFile(fichierzip,"r").namelist() lst.sort(lambda x,y : (cmp(string.upper(x),string.upper(y)))) i=0 for item in lst: i+=1 if int(i/2)*2==i: vprint(item) else: vprint(item.ljust(38)) z.close() except: vprint('Pb Global') def zipvisu(fichierzip): global Gsep,chaineretour try: Gsep=Gsep except: Gsep='\t' chaineretour='' try: z=zipfile.ZipFile(fichierzip,"r") except: vprint('Pb Global') sys.exit(0) zl = z.infolist() zl.sort(lambda x,y : (cmp(string.upper(x.filename),string.upper(y.filename)))) for item in zl: taux=int(100-item.compress_size*100/item.file_size) if item.file_size>100000000: taillef=str(item.file_size/1000000).rjust(7)+' Mo' elif item.file_size>100000: taillef=str(item.file_size/1000).rjust(7)+' ko' else: taillef=str(item.file_size).rjust(7)+' ' if item.compress_size>100000000: taillec=str(item.compress_size/1000000).rjust(6)+' Mo' elif item.file_size>100000: taillec=str(item.compress_size/1000).rjust(6)+' ko' else: taillec=str(item.compress_size).rjust(6)+' ' #vprint(formatDate(item.date_time)+taillef+str(taillec)+str(taux).rjust(3)+"%"+item.CRC+item.filename) vprint(formatDate(item.date_time)+Gsep+taillef+Gsep+str(taillec)+Gsep+' '+str(taux).rjust(3)+"% "+Gsep+str(item.CRC).rjust(12)+' '+Gsep+item.filename) z.close() # c'est là que les athéniens s'éteignirent, car on leur avait coupé l'électricité... if __name__ == '__main__': global Gsep Gsep='' patterns=[] if len(sys.argv)<3: aide() #lecture des arguments j=0 for i in sys.argv: if j==0: script=i if j==1: commande=i if j==2: fichierzip=i if j>2: if string.find(i,";"): for k in string.split(i,";"): patterns.append(k) else: patterns.append(i) j=j+1 tmp=os.path.splitext(fichierzip) # extension '.zip' à ajouter ? if string.upper(tmp[1])<>'.ZIP': if tmp[0][:-1]=="\\": fichierzip=tmp[0][:-1]+'.zip' else: fichierzip=tmp[0]+'.zip' lstfichiers=[] # on collecte les fichiers du répertoire courant for i in os.listdir(os.getcwd()): if not os.path.isdir(i): lstfichiers.append(i) if commande=="T" or commande=="t" or commande=="-T" or commande=="-t": ziptest(fichierzip) if commande=="TT" or commande=="tt" or commande=="-TT" or commande=="-tt" : zipttest(fichierzip) if commande=="L" or commande=="l" or commande=="-L" or commande=="-l" : ziplist(fichierzip) if commande=="V" or commande=="v" or commande=="-V" or commande=="-v": zipvisu(fichierzip) if commande=="PD" or commande=="pd" or commande=="-PD" or commande=="-pd" : # utilise le ZipFile.printdir() standard z=zipfile.ZipFile(fichierzip,"r") z.printdir() if commande=="A" or commande=="a" or commande=="-A" or commande=="-a" : zipappend(fichierzip,patterns) print"fini" if commande=="U" or commande=="u" or commande=="-U" or commande=="-u" : zipupdate(fichierzip,patterns) if commande=="E" or commande=="e" or commande=="-E" or commande=="-e" : zipextract(fichierzip,patterns) if commande=="EE" or commande=="ee" or commande=="-EE" or commande=="-ee" : # équivalent à '-E', mais avec lecture directe # (juste pour montrer du code aux 'dévelop-passionnés') zipeextract(fichierzip,patterns) if commande=="B" or commande=="b" or commande=="-B" or commande=="-b" : vprint("""\r\n\r\n\r\nQuelle est la différence entre Napoléon et un arbre ? \r\n ...\r\n\r\n Ils ont tous les deux des feuilles, sauf Napoléon...\r\n """) if commande=="D" or commande=="d" or commande=="-D" or commande=="-d" : zipdelete(fichierzip,patterns) if commande=="DD" or commande=="dd" or commande=="-DD" or commande=="-dd": """ Ancienne méthode (la première testée, en fait) ; remplacée par '-D' Ici, pour chaque fichier conservé, on le crée sur disque, puis on le recompresse dans le nouveau fichier-zip. A la fin, on supprime l'ancien fichier-zip, et on renomme le nouveau. """ zipddelete(fichierzip,patterns) if commande=="P" or commande=="p" or commande=="-P" or commande=="-p" : vprint("Script :"+script) vprint("Commande :"+commande) vprint("Fichier zip :"+fichierzip) vprint("Patterns :"+patterns) lst,antilst=filter(lstfichiers,patterns) vprint("\r\nListe répertoire :"+lst) vprint("\r\nanti-Liste répertoire :"+antilst) if os.path.isfile(fichierzip): z=zipfile.ZipFile(fichierzip,"r") lst,antilst=filter(z.namelist(),patterns) vprint("\r\n\r\nListe ds fichier zip :"+lst) vprint("\r\nanti-Liste ds fich.zip:"+antilst) if commande=="H" or commande=="h" or commande=="-H" or commande=="-h" : aide(fichierzip[:1]) if commande=="S" or commande=="s" or commande=="-S" or commande=="-s" : pass