Alle doppelten Dateien in einem verzeichnis löschen
andreas
- php
Hallo!
Ich probiere ein PHP-Script zu schreiben, welches alle doppelten Dateien löscht.
Und zwar handelt es sich um ein Verzeichnis, mit einigen 1000 Dateien, die oft gleich sind(erkennbar an gleicher Größe) aber einen anderen Namen haben(wenn "datei" schon existiert wurde oft "datei2" verwendet...., aber leider nach keinem vernünftigen Muster)
Ich dachte da an eine Schleife, in der ich mit filesize() überprüfe ob eine Datei genau so groß ist, wie die aktuelle, und ggfs mit unlink() lösche. Aber ich hab das ein paar grundsätzlicher Probleme.
Wie kann ich innerhalb der Schleife wieder die Dateien weiter durchsuchen, eine Schleife in der Schleife ist doch nicht wirklich gut, oder?
<?php
$handle=opendir ('.');
while (false !== ($file = readdir ($handle))) {
$size1=filesize($file);
$handle2=opendir ('.');
while (false !== ($file2 = readdir ($handle2))) {
$size2=filesize($file2);
if ($size1==$size2){
unlink($file2);}
}
}
closedir($handle);
?>
Wie macht man sowas richtig?
Grüße
Andreas
hi!
Wie kann ich innerhalb der Schleife wieder die Dateien weiter
durchsuchen, eine Schleife in der Schleife ist doch nicht wirklich
gut, oder?
Ich wüsste nicht, was gegen eine Schleife innerhalb einer Schleife
spricht. Allerdings ist es sehr ungünstig, jedesmal wieder die Größe
aller Dateien abzufragen.
Mach es besser so, dass du nur einmal am Anfang den Dateinamen und
die Größe jeder Datei einliest und irgendwo in einer geeigneten
Datenstruktur zwischenspeicherst. Dann kannst du alleine im Speicher
die ganzen Einträge durchgehen und miteinander vergleichen, was
bedeutend schneller geht, als ständige Plattenzugriffe.
Wenn du dabei zwei Dateien mit gleicher Größe erwischst, kannst du
diese zusammen an einer anderen Stelle zwischenspeichern und sofort
bzw. irgendwann später miteinander vergleichen, um eventuelle eine
davon zu löschen.
bye, Frank!
Hi!
Hast recht, das wird das beste sein. Ich kann ja einfach eben alles(Name/Größe) in eine Tabelle schreiben, und dann nach doppelten Einträgen suchen, das wurde ja schon öfter hier diskutiert. Dann habe ich eine nette Liste, die ich evtl noch mit unlink() abarbeiten kann. Frag mich zwar ob ich das nicht lieber von Hand mache, aber so hab ich wenigstesn was dabei gelernt:)
Auch wenns am Ende wahrscheinlich länger dauern wird!(könnte schon bald bei der Hälfte angelangt sein:)
Jedenfalls vielen Dank!
Grüße
Andreas
PS: Eien frage noch: Sollte ich lieber dir() oder lieber readdir() verwenden?Unterschiede?
Moin!
PS: Eien frage noch: Sollte ich lieber dir() oder lieber readdir() verwenden?Unterschiede?
Der Unterschied der beiden besteht darin, dass ich das eine kenne und von dem anderen noch nie was gehoert hab. ;-) Also was zum Teufel ist dir() ?
So long
--
Alle Verallgemeinerungen sind falsch.
hi!
PS: Eien frage noch: Sollte ich lieber dir() oder lieber readdir
() verwenden? Unterschiede?
Der Unterschied der beiden besteht darin, dass ich das eine kenne
und von dem anderen noch nie was gehoert hab. ;-) Also was zum
Teufel ist dir() ?
Vielleicht meint er http://www.php.net/manual/en/class.dir.php?
Anscheinend verwendet das aber auch readdir(), also ist es wohl im
Endeffekt ziemlich egal.
Alle Verallgemeinerungen sind falsch.
Der Babier rasiert genau die, die sich nicht selber rasieren... ;)
bye, Frank!
Moin!
Vielleicht meint er http://www.php.net/manual/en/class.dir.php?
Oh oops, irgendwie bin ich in Gedanken zu Perl ruebergeschwenkt, wo es kein dir gibt. *g*
Alle Verallgemeinerungen sind falsch.
Der Babier rasiert genau die, die sich nicht selber rasieren... ;)
Naja, der Konflikt beim oberen loest sich auf, wenn man annimmt, dass die Aussage falsch ist. Das Barbierproblem ist in der Formulierung, wie Du sie hier bringst, tatsaechlich nicht loesbar. Allerdings wird es auch oft als "Der Barbier rasiert alle Männer, die sich nicht selber rasieren" ausgedrueckt, und dann kann man es imho in einer Weise auffassen, wo sich kein Konflikt ergibt.
So long
--
Alle Verallgemeinerungen sind falsch.
hi!
Vielleicht meint er http://www.php.net/manual/en/class.dir.php?
Oh oops, irgendwie bin ich in Gedanken zu Perl ruebergeschwenkt,
wo es kein dir gibt. *g*
Wie gut, dass daran nicht die Uhrzeit schuld ist... *g*
Alle Verallgemeinerungen sind falsch.
Der Babier rasiert genau die, die sich nicht selber rasieren...
Naja, der Konflikt beim oberen loest sich auf, wenn man annimmt,
dass die Aussage falsch ist.
Das war mir bewusst :)
Das Barbierproblem ist in der Formulierung, wie Du sie hier
bringst, tatsaechlich nicht loesbar. Allerdings wird es auch oft
als "Der Barbier rasiert alle Männer, die sich nicht selber
rasieren" ausgedrueckt, und dann kann man es imho in einer Weise
auffassen, wo sich kein Konflikt ergibt.
Wenn man es so auffassen kann, dass es konfliktfrei lösbar ist, dann
ist es ja langweilig. Wer hat denn neulich gefordert, dass ich meine
Aussagen klarer und eindeutiger formulieren soll? ;)
bye, Frank!
Hi Frank,
Wer hat denn neulich gefordert, dass ich meine
Aussagen klarer und eindeutiger formulieren soll? ;)
keine Ahnung, aber er klingt spontan sympathisch. <eg>
Viele Grüße
Michael
Moin,
Ich probiere ein PHP-Script zu schreiben, welches alle doppelten Dateien löscht.
Au fein, eine Programmiertechnikfrage.
Also ich denke eine der effizientesten Sachen wäre etwas in der Art von
Gehe alle Dateien durch
| Überlege dir für die aktuelle Datei irgendein eindeutiges Erkennungsmerkmal (md5(implode("",file($dateiname))) wäre so eins)
| schau in einem assoziativen Array nach, ob du das Erkennungsmerkmal schon mal gesehen hast (if($deinArray[$erkennungsmerkmal]))
| +-falls ja: lösche die Datei
| +-falls nein: merke dir das Erkennungsmerkmal in dem Array ($deinArray[$erkennungsmerkmal] = true;)
Nachdem die Schleife durchgelaufen ist, hast du von jeder Datei nur eine Kopie (die Benennung dieser Kopie ist nicht deterministisch).
PS: Statt eines assoziativen Arrays kannst du jede andere Struktur nehmen die einfache Überprüfungen, darauf ob ein Objekt in ihr drin ist, zulässt (binäre Bäume irgendwer?). Ich gehe aber mal davon aus dass die PHP-Leute das bei den Arrays schon ganz gut gemacht haben. Statt des implode()-Einzeilers zum Dateiauslesen solltest du vielleicht besser den fopen(); fread(,filesize()); fclose();-Dreizeiler nehmen, der müsste um einiges performanter sein.
--
Henryk Plötz
Grüße von der Ostsee
hi!
Au fein, eine Programmiertechnikfrage.
Warum änderst du dann nicht die Kategorie? ;)
Also ich denke eine der effizientesten Sachen wäre etwas in der
Art von [...]
Nachdem die Schleife durchgelaufen ist, hast du von jeder Datei
nur eine Kopie
Jepp. War ja eigentlich ungefähr das, was ich vorgeschlagen habe.
Nur etwas klarer ausformuliert... ;)
(die Benennung dieser Kopie ist nicht deterministisch).
Was heißt das im Klartext?
PS: Statt eines assoziativen Arrays kannst du jede andere Struktur
nehmen die einfache Überprüfungen, darauf ob ein Objekt in ihr
drin ist, zulässt (binäre Bäume irgendwer?).
Wenn die PHP-Programmierer Ahnung von ihrem Job haben, dann ist
anzunehmen, dass sie die assoziativen Arrays bereits mit vernünftigen
Hashmaps implementiert haben, die theoretisch schneller sein dürften
(meist konstante Zugriffszeit) als eine selbst-implementierte Version
mit binären Bäumen (mindestens logarithmische Zugriffszeit).
bye, Frank!
ps. So spät nachts kann ich vielleicht nicht mehr klar denken. Für
eventuelle Fehler übernehme ich daher keine Garantie... ;)
Moin,
Au fein, eine Programmiertechnikfrage.
Warum änderst du dann nicht die Kategorie? ;)
Och, ich hatte offline geschrieben und zum Kategorieändern muss man online sein, da hatte ich dann doch kein Lust mehr drauf.
(die Benennung dieser Kopie ist nicht deterministisch).
Was heißt das im Klartext?
Ich wollte nur noch mal "The filenames are not returned in any particular order." (aus der readdir()-Doku) erwähnt haben. Dieser Algorithmus behält die Kopie übrig die readdir() als erstes ausspuckt, und das ist eher selten etwa die die in der alphabetischen Sortierung (oder irgendeiner anderen Sortierung) vorne steht. Wenn du also "Datei", "Kopie von Datei" und "Kopie von Kopie von Datei"(verdammt, ich hab die letzten Tage zuviel Zeit vor einem Windows-Rechner verbracht ;) hast, dann bleibt heute vielleicht Kopie von Datei, morgen Datei und übermorgen die kopierte Kopie übrig.
Andreas: Wenn du auch noch eine alphabetisch oder sonstwie sortierte Version übrigbehalten willst, musst du erst alle Dateinamen in ein Array einlesen, dieses dann mit einem Sortieralgorithmus deiner Wahl bewerfen (http://www.php.net/manual/de/function.natcasesort.php zum Beispiel) und dann die Elemente dieses Arrays mit dem Algorithmus durchgehen.
--
Henryk Plötz
Grüße von der Ostsee
Moin,
Au fein, eine Programmiertechnikfrage.
Warum änderst du dann nicht die Kategorie? ;)
ja, aber auch [PHP] :)
Was mich noch interessieren würde, wann verwendet man fopen()... und wann opendir(), readdir()...?
Ich verstehe irgendwie nicht ganz den Unterschied?! Dachte immer mit fopen() öffnet man die Datei, aber warum sollte man das? Es reichen doch Name und Größe zu wisssen und entsprechend zu löschen oder zu kopieren oder wie auch immer! fopen() sollte dagegen doch recht langsam sein, wenn erst alle Dateien geöffnet werden, oder denke ich hier irgendwie falsch?
Grüße
Andreas
Hoi !
Was mich noch interessieren würde, wann verwendet man fopen()... und wann opendir(), readdir()...?
Ich verstehe irgendwie nicht ganz den Unterschied?! Dachte immer mit fopen() öffnet man die Datei, aber warum sollte man das? Es reichen doch Name und Größe zu wisssen und entsprechend zu löschen oder zu kopieren oder wie auch immer! fopen() sollte dagegen doch recht langsam sein, wenn erst alle Dateien geöffnet werden, oder denke ich hier irgendwie falsch?
Es kann Dir durchaus passieren, daß Du zwei oder noch mehr Dateien mit identischer Größe aber total unterschiedlichem Inhalt hast. Wenn Du nur die Größen vergleichst, dann löscht Du mit Sicherheit eine der Dateien (trotzdem sie von der übriggebliebenen verschieden ist).
Henryk benutzt deshalb für seine Lösung den MD5-Wert (eine Art Quersumme) der Datei: Damit kannst Du ziemlich sicher (99,9999999999999999999(usw.)%) alle doppelten Dateien entfernen, und jeweils ein Exemplar behalten, egal, ob sie die gleiche Größe haben oder nicht.
Dafür ist die Lösung von Henryk in der Tat _wesentlich_ langsamer.
Ciao,
Harry