Allle Datein von der Festplatte in eine Liste eintragen



  • Hallo,

    leider find ich den hier angesprochenen FAQ-Beitrag nicht!!!!



  • // SB ist die Statusleiste
    // SubDirs ist eine Optionsschalter
    // DirList ist ein Memofeld
    // FileAnz ist ein Label
    // PathMode ist ein Optionsfeld (Index 0,1,2 zur Auswahl)
    // Edit1 ist ein Textfeld für das Dateisuchmuster
    // **(*.* oder .exe oder .JPG oder ... )

    // Parameter Root zeigt Startdirectory - OHNE Dateiname/Platzhalter !!!

    void __fastcall TDirListForm::Search(AnsiString Root)
    {
      TStringList *Dirs=new TStringList();
      TSearchRec f;
      int FFRes;
      AnsiString Verz;
      SB->SimpleText="Suche in: " + Root;
      if (Root[Root.Length()]=='\\')
        Verz=Root+"*.*";
      else
        Verz=Root+"\\*.*";
      FFRes=FindFirst(Verz,0x10,f);   /* Verzeichnisse suchen */
      if (FFRes==0)
      {
        while (FFRes==0)
        {
          if ((f.Attr&0x10)==0x10)
          {
            ;//Dir
            if (Subdirs->Checked)
              if (f.Name[1]!='.')
                Dirs->Add(f.Name);
          }
          FFRes=FindNext(f);
        }
        FindClose(f);
      }
      if (Root[Root.Length()]=='\\')
        Verz=Root + Edit1->Text;
      else
        Verz=Root + "\\" + Edit1->Text;
      FFRes=FindFirst(Verz,0x20,f);   /* Dateien suchen */
      if (FFRes==0)
      {
        if (PathMode->ItemIndex==1)
        {
          if (DirList->Lines->Count>0)
            DirList->Lines->Add("");
          DirList->Lines->Add(Root);
          DirList->Lines->Add("");
        }
        while (FFRes==0)
        {
          if ((f.Attr&0x10)!=0x10)
          {
            ;//File
            if (PathMode->ItemIndex==2)
            {
              if (Root[Root.Length()]=='\\')
                DirList->Lines->Add(Root+f.Name);
              else
                DirList->Lines->Add(Root+"\\"+f.Name);
            }
            else
            {
              DirList->Lines->Add(f.Name);
            }
            FileAnz->Caption=FileAnz->Caption.ToInt()+1;
          }
          FFRes=FindNext(f);
        }
        FindClose(f);
      }
      for (int i=0;i<Dirs->Count;i++)
      {
        Update();
        if (Root[Root.Length()]=='\\')
          Search(Root+Dirs->Strings[i]);
        else
          Search(Root+"\\"+Dirs->Strings[i]);
      }
      delete Dirs;
    }
    


  • Gibt es eigentlich auch eine schnellere Methode oder ist das die schnellste????
    Als ich den code auf meiner kleinsten Partition ausgeführt habe hat das mindestens 10 mins gedauert. Würde es schneller gehen, wenn man die Ordner und Dateinamen nicht in einem Memo sonder in einem String speichert?!

    Oder gibt es sonst noch möglichkeiten um den Vorgang zu beschleunigen???



  • Dateiensuchen schrieb:

    Gibt es eigentlich auch eine schnellere Methode oder ist das die schnellste????
    Als ich den code auf meiner kleinsten Partition ausgeführt habe hat das mindestens 10 mins gedauert. Würde es schneller gehen, wenn man die Ordner und Dateinamen nicht in einem Memo sonder in einem String speichert?!
    Oder gibt es sonst noch möglichkeiten um den Vorgang zu beschleunigen???

    bei mir braucht

    dir c:\*.* /S /B > dir.txt
    

    ca 2,3 minuten.
    sind 426595 dateien.
    ich kann mir sehr gut vorstellen, daß das viermal so lange braucht, um es in feine GUI-objekte zu stopfen. also ich kann mir gut virstellen, daß du am optimum bei diesem ansatz bist.



  • Wie meinst du das???
    ist

    dir c:\*.* /S /B > dir.txt
    

    eine weitere Funktion um Dateien zu suchen?! Wie kann man die denn compilieren?

    Ich habe in der zwischenzeit mal probiert, das in nen String zu packen. Klappt jetzt um einiges schneller!!!!



  • Hallo nochmal....
    ich habe mein Problem gefunden. Ich glaube aber, dass es ein Fehler im Compiler ist. Wenn ich folgenden Code ausführe, speichert das Programm nach jedem finden einer Datei den Pfad in eine Textdatei. Es soll aber NACHDEM alle Dateien gefunden wurden die gesamte Liste EINMAL speichern.

    Hier der Code:

    void __fastcall TDirListForm::Search(AnsiString Root) 
    { 
      TStringList *Dirs=new TStringList(); 
      TSearchRec f; 
      int FFRes; 
      AnsiString Verz; 
      SB->SimpleText="Suche in: " + Root; 
      if (Root[Root.Length()]=='\\') 
        Verz=Root+"*.*"; 
      else 
        Verz=Root+"\\*.*"; 
      FFRes=FindFirst(Verz,0x10,f);   /* Verzeichnisse suchen */ 
      if (FFRes==0) 
      { 
        while (FFRes==0) 
        { 
          if ((f.Attr&0x10)==0x10) 
          { 
            ;//Dir 
            if (Subdirs->Checked) 
              if (f.Name[1]!='.') 
                Dirs->Add(f.Name); 
          } 
          FFRes=FindNext(f); 
        } 
        FindClose(f); 
      } 
      if (Root[Root.Length()]=='\\') 
        Verz=Root + Edit1->Text; 
      else 
        Verz=Root + "\\" + Edit1->Text; 
      FFRes=FindFirst(Verz,0x20,f);   /* Dateien suchen */ 
      if (FFRes==0) 
      { 
        if (PathMode->ItemIndex==1) 
        { 
          if (DirList->Lines->Count>0) 
            DirList->Lines->Add(""); 
          DirList->Lines->Add(Root); 
          DirList->Lines->Add(""); 
        } 
        while (FFRes==0) 
        { 
          if ((f.Attr&0x10)!=0x10) 
          { 
            ;//File 
            if (PathMode->ItemIndex==2) 
            { 
              if (Root[Root.Length()]=='\\') 
                DirList->Lines->Add(Root+f.Name); 
              else 
                DirList->Lines->Add(Root+"\\"+f.Name); 
            } 
            else 
            { 
              DirList->Lines->Add(f.Name); 
            } 
            FileAnz->Caption=FileAnz->Caption.ToInt()+1; 
          } 
          FFRes=FindNext(f); 
        } 
        FindClose(f); 
      } 
      for (int i=0;i<Dirs->Count;i++) 
      { 
        Update(); 
        if (Root[Root.Length()]=='\\') 
          Search(Root+Dirs->Strings[i]); 
        else 
          Search(Root+"\\"+Dirs->Strings[i]); 
      }
      DirList->Lines->SaveToFile("dateien.txt");  // HIER IST DAS PROBLEM
      delete Dirs; 
    }
    

    In der drittletzten Zeile ist der Fehler. Das Programm sucht Dateien und wenn es eine Datei gefunden hat, dann wird sie in die Textdatei gespeichert. Ich will aber, dass das Programm erst alle Dateien in das Memo speichert und dann den Inhalt des Memos in die Datei. Das müsste viel schneller sein. Deshalb steht " DirList->Lines->SaveToFile("dateien.txt");" auch außerhalb der Such-schleife. Wenn ich die Zeile " DirList->Lines->SaveToFile("dateien.txt");" auskommentiere, braucht das Programm für den Suchdurchlauf ca. 70s wenn ich es drinn lasse ca. 20 mins.

    Weiss jemand wo das problem liegt, oder ist das wirklich ein Fehler beim Compilieren?



  • Du hast schon gesehen, dass die Funktion Search(...) rekursiv arbeitet ? 🕶 🕶 🕶

    Das Speichern darf NICHT in der Funktion erfolgen, erst wenn diese nach dem Aufruf aus dem Hauptprogramm zurückkommt!

    Ansonsten speichert der immer, wenn er aus einer Rekursion zurückkommt.

    Du kannst höchstens einen Zähler einbauen, dr mit jeder Rekursion hochzählt und danach wieder runter. Bei Zähler = Null (oder 1) bist Du in der ersten Rek.- Ebene.

    Gruss
    Frank



  • Bei meinem Vorschlag gehe ich von einen TreeView statt eines ListView aus, vielleicht ist das ja eine Lösung.
    Reicht es nicht aus, zunächst nur die Dateien und Unterverzeichnisse des aktuellen Verzeichnisses/Laufwerks einzulesen. Erst wenn jemand einen Knoten erweitert muss man das entsprechende Verzeichnis einlesen und die Daten des TreeView anpassen.



  • Dateiensuchen schrieb:

    Gibt es eigentlich auch eine schnellere Methode oder ist das die schnellste????
    Als ich den code auf meiner kleinsten Partition ausgeführt habe hat das mindestens 10 mins gedauert. Würde es schneller gehen, wenn man die Ordner und Dateinamen nicht in einem Memo sonder in einem String speichert?!

    Tatsächlich nimmt das Unterbringen in einer GUI-Komponente einen wesentlichen Anteil der Zeit ein. Separates Abspeichern in nicht UI-abhängigen Datenstrukturen und Darstellung nach Bedarf sollte spürbare Verbesserungen bringen. Das kannst du beispielsweise so umsetzen, wie _DocShoe_ vorschlägt - aber du kannst auch schon alle Daten einlesen und nur die Übertragung ins TreeView bedarfsgemäß verzögern.



  • Hallo

    Ich habe da auch noch eine Idee.
    Zumindes habe ich es so gemacht.

    Für die Auslesung der Verzeichnisse verwendest du mehrere Threads z.B. 3
    So kannst du dann immer gleichzeitig 3 verzeichnisse einlesen.
    Die gefundenen Resultate speicherst du beispielsweise in einem Map-Container (für meine Bedürfnisse war er bis jetzt immer schnell und stabil).

    Meine Anwendung brauch so jetzt für 191'000 Dateien + Laden in eine ListBox min. 35 Sekunden.

    PS: Wenn du die Verzeichnisse zum erstenmal ausliest und anschliessend nochmals, so läuft der zweite Durchgang tausig mal schneller 🙂

    Bei mir war es sol. Erster Durchlauf (ca. 2.5 Minuten), zweiter durchlauf (35 Sekunden).


Anmelden zum Antworten