1 | import os, stat, sys |
---|
2 | import hashlib |
---|
3 | |
---|
4 | |
---|
5 | |
---|
6 | class FileDB: |
---|
7 | |
---|
8 | fields = ["name","path","signature","md5"] |
---|
9 | md5 = True |
---|
10 | |
---|
11 | |
---|
12 | |
---|
13 | def __init__(self,obj): |
---|
14 | """ |
---|
15 | Instanciation de la base de donnees a partir d'un repertoire ou d'un fichier de sauvegarde |
---|
16 | """ |
---|
17 | if os.path.isdir(obj): |
---|
18 | self._mapDirectory(obj) |
---|
19 | elif os.path.isfile(obj): |
---|
20 | self._loadFromFile(obj) |
---|
21 | else : |
---|
22 | raise Exception(str(obj)+" is not a valid address") |
---|
23 | |
---|
24 | def __repr__(self): |
---|
25 | return "A file database instance" |
---|
26 | |
---|
27 | def __str__(self): |
---|
28 | """ |
---|
29 | Affichage du contenu de l'instance |
---|
30 | """ |
---|
31 | res = [] |
---|
32 | for l in self._db: |
---|
33 | res.append(os.path.join(l["path"],l["name"])+" ==> "+l["signature"]) |
---|
34 | |
---|
35 | return "\n".join(res) |
---|
36 | |
---|
37 | |
---|
38 | def _loadFromString(self,str): |
---|
39 | """ |
---|
40 | Chargement ou rechargement du contenu de la base de donnee a partir d'une chaine de caractere au format CSV |
---|
41 | """ |
---|
42 | self._db = [dict(zip(FileDB.fields,f.split(";"))) for f in str.split("\n")] |
---|
43 | |
---|
44 | def _loadFromFile(self,file): |
---|
45 | """ |
---|
46 | Chargement ou rechargement du contenu de la base de donnee a partir d'un fichier CSV |
---|
47 | """ |
---|
48 | content = open(file,"r").read() |
---|
49 | self._loadFromString(content) |
---|
50 | |
---|
51 | def _mapDirectory(self,dir): |
---|
52 | """ |
---|
53 | Parcours le repertoire dir et stocke son arborescence dans la memoire interne de l'instance |
---|
54 | La recusion est faite dans le os.walk |
---|
55 | """ |
---|
56 | self._db = [] |
---|
57 | for root, dirs, files in os.walk(dir): |
---|
58 | for name in files: |
---|
59 | fileNode = {} |
---|
60 | fileNode["name"] = name |
---|
61 | fileNode["path"] = os.path.abspath(root) |
---|
62 | fileNode["signature"] = str(FileDB._signature(os.path.join(root,name))) |
---|
63 | if FileDB.md5: |
---|
64 | fileNode["md5"] = FileDB.md5file(os.path.join(os.path.abspath(root),name)) |
---|
65 | else: |
---|
66 | fileNode["md5"] = "" |
---|
67 | self._db.append(fileNode) |
---|
68 | |
---|
69 | def save(self,file): |
---|
70 | """ |
---|
71 | Ecrit le contenu de la BDD au format CSV |
---|
72 | """ |
---|
73 | content=[] |
---|
74 | for line in self._db: |
---|
75 | tempLine=[] |
---|
76 | for field in FileDB.fields: |
---|
77 | tempLine.append(line[field]) |
---|
78 | content.append(";".join(tempLine)) |
---|
79 | |
---|
80 | out = open(file,"w") |
---|
81 | out.write("\n".join(content)) |
---|
82 | |
---|
83 | def isInDb(self,file): |
---|
84 | """ |
---|
85 | Recherche si un fichier est present dans la base de donnees (nom et signature sont compares) |
---|
86 | Retourne la liste des fichiers correspondant, liste vide si aucun element |
---|
87 | """ |
---|
88 | if not(os.path.isfile(file)): |
---|
89 | raise Exception(file + " not found") |
---|
90 | |
---|
91 | dirName, fileName = os.path.split(file) |
---|
92 | sig = FileDB._signature(file) |
---|
93 | results = [elm for elm in self._db if elm["name"] == fileName and elm["signature"]==str(sig)] |
---|
94 | |
---|
95 | if FileDB.md5: |
---|
96 | md5 = FileDB.md5file(file) |
---|
97 | results = [elm for elm in self._db if elm["name"] == fileName and elm["md5"]==str(md5)] |
---|
98 | |
---|
99 | return [os.path.join(elm["path"],elm["name"]) for elm in results] |
---|
100 | |
---|
101 | |
---|
102 | @staticmethod |
---|
103 | def _signature(file): |
---|
104 | """ |
---|
105 | Cree une signature du fichier (mode, taille en octet, date de modification) |
---|
106 | """ |
---|
107 | st = os.stat(file) |
---|
108 | return (stat.S_IFMT(st.st_mode), |
---|
109 | st.st_size, |
---|
110 | st.st_mtime) |
---|
111 | |
---|
112 | # commente car pb avec python 2.4 et 2.5 |
---|
113 | # chunksize depend de la machine il faudra optimiser |
---|
114 | |
---|
115 | @staticmethod |
---|
116 | def md5file(fileName,chunksize=13): |
---|
117 | md5 = hashlib.md5() |
---|
118 | f = open(fileName,'rb') |
---|
119 | for chunk in iter(lambda: f.read(2**chunksize), b''): |
---|
120 | md5.update(chunk) |
---|
121 | f.close() |
---|
122 | return md5.hexdigest() |
---|
123 | |
---|
124 | |
---|
125 | if __name__ == "__main__": |
---|
126 | db = FileDB('.') |
---|
127 | db.save('XDR-FileDB.csv') |
---|