Bonsoir,
le titre n'est pas top mais je ne sais pas trop comment le dire autrement.
Tout le monde sait que dans une boucle il faut rendre la main au système sinon on se retrouve avec un prog qui a l'air planté, et on rajoute donc Application.ProcessMessages; dans le corps de la boucle.
Et comme c'est time consuming il parait, on l'applique de temps en temps, genre
J'ai un dossier qui contient 4 sous-dossiers, chacun contenant des fichiers en nombre et taille variables.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 for i := 0 to grand_nombre-1 do begin taf_avec(i); if (i mod 10 = 0) then Application.ProcessMessages; end;
Il y en a beaucoup alors je veux les trier en sous-sous-dossiers, genre tous les 50 fichiers je crée un dossier et j'y déplace les 50 fichiers, et ça, tant qu'il y a des fichiers.
Avant de lancer ça dans la vraie vie (environ 600 000 fichiers, rien que ça !), j'ai monté un dossier de simulation qui contient 4 sous-dossiers avec respectivement 10, 5, 1 et 0 fichiers, et je définis maxfiles à 3.
Je m'attends donc après l'exécution à avoir 4 sous-sous-dossiers dans le premier sous-dossier avec 3, 3, 3, 1 fichiers,
à avoir 2 s-s-d dans le deuxième avec 3 et 2 fics, 1 s-s-d dans le troisième avec 1 fic et rien dans le quatrième.
On est d'accord jusque là ?
Je pose la question ici parce que c'est juste après qu'on rigole et que ça devient tendu…
D'abord j'ai estimé que, dans chaque sous-dossier, le dernier s-s-d n'aurait pas besoin d'Application.ProcessMessages; dans sa boucle de remplissage, puisque c'est la dernière étape et que le nombre de fichiers sera toujours inférieur à 50 (3 en test), et j'ai donc positionné cette respiration à la fin de la boucle gérant l'autre cas, quand il faut travailler avec des boucles de 50 (3 en test), qui commencent par la création d'un nouveau dossier pour les accueillir.
C'est clair ?
Parce que quand j'exécute sur mes 16 fichiers de test, le résultat est complètement en vrac (sauf pour le dossier vide, qui reste toujours vide).
Oui oui, vous avez bien lu, par exemple j'ai relevé ce soir ça comme résultat :
dans le 1er s-d (10 fichiers au départ), 2 s-s-d (au lieu de 4), le 1er contenant 5 fichiers, le 2e contenant les 2 autres s-s-d et 1 fic.
dans le 2e s-d, 1 seul s-s-d (au lieu de 2) qui contient ses 3 fichiers prévus et l'autre s-s-d avec 2 fichiers.
le 3e s-d est correct avec 1 s-s-d contenant 1 fichier, comme prévu.
et le 4e ne contient rien, puisqu'il ne contenait rien au départ.
J'essaye un croquis
Bon bref, c'est une pagaille immonde et impossible à mettre en prod'…
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 au départ | attendu | trouvé ----------------|------------|------------ sd1 10 fichiers | ssd1 3 fic | ssd1 5 fic | ssd2 3 fic | ssd2 1 fic + ssd3 3 fic + ssd4 1 fic | ssd3 3 fic | | ssd4 1 fic | sd2 5 fichiers | ssd1 3 fic | ssd1 3 fic + ssd2 2 fic | ssd2 2 fic | sd3 1 fichier | ssd1 1 fic | ssd1 1 fic sd4 vide | rien | rien
Et pourtant l'algo est correct.
Oui oui, je vous entends hurler "mais kess t'en sais ? C'est toi qui t'es fichu dedans, etc."
Ben non.
Parce qu'il suffit que je rajoute des lignes de log plein les boucles pour que miraculeusement, ça tombe en marche correcte.
Les lignes de log consistent à ajouter à un TMemo une ligne contenant le nom du fichier qui va être déplacé, avec un suivi de compteur, le tout suivi d'un Application.ProcessMessages; bien sûr.
Le problème, c'est que sur 16 fichiers je n'ai pas le temps de voir l'impact de ces respirations sur la durée d'exécution, mais si, au lieu d'une respiration tous les 50 fichiers soit 12000 pour la globalité des fichiers, la chose passe 600 000 respirations, combien de temps ça dure, une respiration ?
Allez, tiens, le code (les appels genre MakeFolder ont des noms suffisament sympas pour que je me dispense de les joindre, ça allège) :
Vous voyez les lignes de log commentées (sauf la respiration principale) donc génératrices de résultats en vrac, il suffit de décommenter les 4 lignes pour que ça soit bon.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 procedure TForm1.WorkOnDossier(chemin: string; count: integer); var d,i: integer; maxfiles: integer; racine: string; src,dst: string; begin maxfiles := 3; racine := copy(chemin, Length(chemin)-2, 3)+'_'; d := 0; while count > maxfiles do begin inc(d); dst := chemin+'/'+racine+IntToStr(d); MakeFolder(dst); //log(dst + ' -a '+IntToStr(d)); for i := 0 to maxfiles-1 do begin src := chemin+'/'+laliste[(maxfiles*(d-1))+i]; MoveFilesFromTo(src, dst); //log(src + ' -a'+' -c'+IntToStr(count)); end; dec(count, maxfiles); // tous les maxfiles, respirer un coup : log(chemin + ' ' +racine+IntToStr(d)) end; // fichiers restants if count > 0 then begin inc(d); dst := chemin+'/'+racine+IntToStr(d); MakeFolder(dst); //log(dst + ' -b '+IntToStr(d)); while count > 0 do begin for i := 0 to count-1 do begin src := chemin+'/'+laliste[(maxfiles*(d-1))+i]; MoveFilesFromTo(src, dst); //log(src + ' -b'+' -c'+IntToStr(count)); dec(count); end; end; end; end;
Une idée pour que ça soit bon sans passer 3 jours à l'exécution (ou plus, peut-être) ?
Merci d'avoir lu tout ça.
Partager