Festplatte katalogisieren
-
Das ist eines der logistisch am schwersten zu lösenden Programme die ich jemals
geschrieben habe und fange jetzt schon zum dritten mal von vorne an.
Ich verlier mit der Zeit den Überblick in meiner Methode und beim "korrigieren"
mach ichs nur schlimmer.Hier etwas Code:
DLB = DirectoryListBox
FLB = FileListBox
DOUT = DirectoryOutline
RICH = RichEdit
LB = ListBoxvoid READ(void) { Form1->RICH->Lines = Form1->FLB->Items; ShowMessage(Form1->RICH->Text.c_str()); Form1->KomponentenNamen += Form1->RICH->Text.c_str(); } void Child(void) { std::string Parent = Form1->DLB->Directory.c_str(); int Childreen = Form1->DLB->Items->Count - (Form1->DLB->ItemIndex); int i = 0; while (i < Childreen) { i++; ShowMessage("Child"); Form1->FLB->Directory = Form1->DLB->Directory; READ(); Form1->DLB->ItemIndex++; Form1->DLB->OpenCurrent(); Form1->FLB->Directory = Form1->DLB->Directory; } } void Suchen(void) { int Childreen = Form1->DLB->Items->Count - (Form1->DLB->ItemIndex); Form1->DESTICHILDCOUNT = Childreen; int i = 0; std::string DESTINATION = Form1->DLB->Directory.c_str(); /* ShowMessage(DESTINATION.c_str()); ShowMessage(IntToStr(Form1->DLB->Items->Count).c_str()); ShowMessage(IntToStr(Form1->DLB->ItemIndex+1).c_str()); */ while (i < Childreen) { i++; ShowMessage("Call Child"); Form1->Current_Child++; Child(); Form1->DLB->ItemIndex--; Form1->DLB->OpenCurrent(); int x = 1; while (x < Form1->Current_Child) { x++; Form1->DLB->ItemIndex++; } } } __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::SpeedButton1Click(TObject *Sender) { DOUT->Directory = "C:\\A Katalogia Test MULTI"; DLB->Directory = DOUT->Directory; DESTICHILDCOUNT = 0; Current_Child = 0; // SCHLEIFE ! // ShowMessage("PAUSE"); Suchen(); RICH->Text = KomponentenNamen.c_str(); LB->Items = RICH->Lines; } //---------------------------------------------------------------------------
ist etwas viel, lässt sich aber nicht lokal beschränken.
Ich lasse zum Test den Ordner "A Katalogia Test MULTI" katalogisieren.in dem ordner sind die dateien Read Main 1.txt und Read Main 2.txt
dann sind darin noch zwei unterordner Child 1 und Child 2
in diesen sind jeweils wieder 2 Dateien.Das Programm soll Jede Datei aus allen Ordner 1 mal in die Liste schreiben.
aber folgendes tut er:Liest Dateien im Hauptordner
Liest 2* im ersten Unterordner
Liest Im Hauptordner
Liest 2* im ersten Unterordner
Liest im zweiten UnterordnerWas zu Hölle ist denn so komplett falsch an diesem Code und es sind vermutlich
mehrere Dinge.(Wenn ihr mir ein paar Befehle geben könntet die das alles einfacher machen, wäre das sehr nett, denn mir fällt nur eine solche Lösung ein)
-
das geht wirklich bei dir so zu kompilieren?
ein Tip:
Verwende den Debugger statt der undefinierten ShowMessages, siehe hierzu auch den Beitrag in den FAQ.[Edit1]der Fehler ist recht einfach: du liest bei beiden while-Schleifen auch die Unterordner immer wieder aus, also solltest du die Schleife nur in einer der Funktionen machen. Im Prinzip solltest du dich aber mal mit Rekursionen beschäftigen....
[Edit2]du kannst als Alternative zu den ganzen Komponenten natürlich auch mit FindFirst/FindNext arbeiten und dort die Suchkriterien entsprechend nach Verzeichnissen und Dateien einstellen. Hierbei ist eine Rekursion auf jdenfall sinnvoll. Ich glaub hier im Forum war auch schonmal ein ähnliches Beispiel...
-
Außerdem solltest du statt der freien Funktionen "Read", "Child" und "Suchen" besser Klassenmethoden erstellen. Dann benötigst du auch nicht immer den Zugriff mittels "Form1->" (und wenn schon dann übergib diesen als Parameter!!!)
Desweiteren sollten Funktionen ohne Parameter in C++ einfach als "()" und NICHT als "(void)" daklariert werden.
Am besten ist, du liest dich noch mal in die objektorientierte Programmierung ein. Evtl. erst mal ein einfacheres Programm programmieren, denn wie Linnea schon geschrieben hat, ohne Rekursion wirst du die Ordner und Dateien nicht korrekt auslesen können (und dazu gehört u.a. das Wissen umd die Verwendung von Funktionsparametern).
Sorry, ich weiß, jeder Anfang ist schwer, aber so ein Code-Gefrickel fördert nicht das Programmieren, sondern erzeugt mehr und mehr Frust (so wie ich deine Kommentare deute, ist es bei dir schon soweit).
-
Gab es mit FindFirst/FindNext nicht Probleme in Verbindung mit einer rekursiven Funktion? Ich meine hier mal so was gelesen zu haben...
Wie auch immer, ich hab das mittels FindFirst/FindNext in Verbindung mit zwei TStirngList-Instanzen gelöst. Beim Einlesen mit FindFirst/FindNext prüfe ich ob, es eine Datei, oder ein Verzeichnis ist. Dateien kommen in die eine TStringList, Verzeichnisse in die andere TStringList. In der TStringList für Verzeichnisse trage ich das / die Startverzeichnis(se) ein. Wann immer ein weiteres Verzeichnis bei der Suche gefunden wird, wird es in diese Liste eingetragen. Wenn ein Verzeichnis komplett abgearbeitet ist, wird es aus dieser Liste gelöscht. Sobald diese Liste leer ist, ist die Suche komplett abgeschlossen.
-
Th69 schrieb:
Desweiteren sollten Funktionen ohne Parameter in C++ einfach als "()" und NICHT als "(void)" daklariert werden.
Das hab ich noch nie gehört. Ich hab gelesen, dass das bei C++ absolut keinen Unterschied macht. Bei C hingegen schon.
-
bei einem "()" statt "(void)" meckert er rum. ich weiß nicht was genau aber er will umbedingt, dass da etwas steht, sonst hat er "zu wenige Parameter".
Ja als Klassenmember... ja das wäre schlau gewesen mach ich gleich.
Rekursion, hört sich kompliziert an aber ich guck mirs mal an.
ich halt euch auf dem laufenden
-
Hallo
Fakt ist : In C geht nur (void).
In C++ kann man (void) schreiben. Ist aber veraltet, man sollte immer () schreiben.Wenn du in C++ "Fehler" bei () bekommst machst du irgendetwas falsch.
bis bald
akari
-
Bei Wikipedia habe ich folgendes zur Methode rekursiver Implementation ( :p ) gefunden:
void fnTraverse( char* pString ) { if( *pString == 0x0 ) return; else // z. B. Buchstabe für Buchst. ausgeben fnTraverse( ++pString ); }
++pString
was zur hölle soll denn das (bringen)?
-
Hallo
Das gehört zum Thema Zeigerarithmetik. Der Wert von pString wird um eins erhöht und als Argument an den nächsten Aufruf von fnTraverse übergeben. Dadurch zeigt pString beim nächsten Aufruf auf das nächste Zeichen in der Zeichenkette.
bis bald
akari
-
Vielleicht kannst du das gebrauchen:
void TextFileSearch(String Path,TStringList *files) { Path=IncludeTrailingBackslash(Path); HANDLE FH; WIN32_FIND_DATA fdat; String Ffile=Path+"\\*"; FH=FindFirstFile(Ffile.c_str(),&fdat); while (FindNextFile(FH,&fdat)) { Ffile=fdat.cFileName; if (fdat.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY && Ffile != ".." && Ffile !=".") { TextFileSearch(Path+fdat.cFileName,files); } else if (ExtractFileExt(fdat.cFileName)==".txt") { files->Add(Path+fdat.cFileName); } } FindClose(FH); }
-
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; } void __fastcall TDirListForm::ListClick(TObject *Sender) { if (Clear->Checked) { DirList->Clear(); FileAnz->Caption=0; } Search(DOLE->Directory); SB->SimpleText=""; }
FileAnz ist ein TLabel
DOLE ist eine eigene Kompo - liefert einen kompletten Pfad als Start für Suche
DirList ist ein TMemo
PathMode ist eine Optionsauswahl (NoPath Grouped FullPath = 0 .. 2)
SubDirst ist ein OptionskästchenGruss
Frank
-
Vielen Dank für die Mühe aber:
1. Was ist SB (SimpleText ???)
2. Es kommt SOFORT beim starten zum stack overflow, hab ichs falsch eingebaut ???
-
Hallo
Der Stackoverflow deutet darauf hin das die Rekursionstiefe zu hoch ist. Sprich du hast zu viele verschachtelte Unterverzeichnisse, die sich dadurch immer wieder aufrufende Search-Funktion belegt dann schnell den ganzen Stack und das Programm muß beendet werden.
Falls das der Grund ist, must du die rekursive Funktion in eine iterative umschreiben.bis bald
akari
-
Bevor ich jetzt dran rumwerkel mach ichs noch mal selbst, nicht weil ich zu blöd für wäre, aber es ist doch der sinn das ichs lerne selbst zu schreiben, außerdem fühle ich micht dann nicht zufrieden.
EDIT: Ich werde mich aber an dem Code orientieren
aber was ist noch die Komponente SB ?
-
void MAINPROCESSVOID(void) { ofstream Katalog; Katalog.open(Katalog_on_Drive.c_str(),ios::binary); SearchFin = false; breaker = 0; Form1->DIB->ItemIndex = 0; Form1->FLB->ItemIndex = 0; Folder4 = 0; while (SearchFin == false && breaker == 0) { Form1->DIB->ItemIndex = Form1->DIB->ItemIndex+1; Form1->Gauge1->Progress++; Form1->Refresh(); Sleep(1); Folder4++; Form1->DIB->OpenCurrent(); if (true) { Form1->FLB->Directory = Form1->DIB->Directory; } Form1->DIB->ItemIndex = Form1->DIB->ItemIndex+1; Form1->FLB->ItemIndex = 0; std::string Name_Zeile = ""; // MessageBox(NULL,"Pause","Debug Mode",MB_OK); if (Form1->FLB->Items->Count > 0) { while (Form1->FLB->ItemIndex+1 < Form1->FLB->Items->Count) { // MessageBox(NULL,FLB->FileName.SubString(FLB->FileName.Length()-3,4).c_str(),"Debug Mode",MB_OK); if (Form1->FLB->FileName.SubString(Form1->FLB->FileName.Length()-3,4)==".mp3" || Form1->FLB->FileName.SubString(Form1->FLB->FileName.Length()-3,4)==".wav" || Form1->FLB->FileName.SubString(Form1->FLB->FileName.Length()-3,4)==".avi" || Form1->FLB->FileName.SubString(Form1->FLB->FileName.Length()-3,4)==".wma") { // MessageBox(NULL,"True","Debug Mode",MB_OK); Name_Zeile = Form1->FLB->FileName.c_str(); Name_Zeile += "\n"; Katalog << Name_Zeile; } Form1->FLB->ItemIndex = Form1->FLB->ItemIndex+1; } if (Form1->FLB->ItemIndex+1 == Form1->FLB->Items->Count) { Form1->Gauge2->Progress = 0; Form1->Gauge2->MaxValue = Form1->FLB->Items->Count+1; if (Form1->FLB->FileName.SubString(Form1->FLB->FileName.Length()-3,4)==".mp3" || Form1->FLB->FileName.SubString(Form1->FLB->FileName.Length()-3,4)==".wav" || Form1->FLB->FileName.SubString(Form1->FLB->FileName.Length()-3,4)==".avi" || Form1->FLB->FileName.SubString(Form1->FLB->FileName.Length()-3,4)==".wma") { // MessageBox(NULL,"True","Debug Mode",MB_OK); Name_Zeile = Form1->FLB->FileName.c_str(); Name_Zeile += "\n"; Katalog << Name_Zeile; Form1->Gauge2->Progress++; } } } // MessageBox(NULL,"Pause","Debug Mode",MB_OK); if (Form1->DIB->ItemIndex+1 == Form1->DIB->Items->Count) { Form1->DIB->Directory = destidir.c_str(); int i = 0; while (i < Folder4) { Form1->DIB->ItemIndex++; // MessageBox(NULL,"Pause","Debug Mode",MB_OK); i++; } //DIB->OpenCurrent(); } if (Form1->DIB->ItemIndex+1 == Form1->DIB->Items->Count) { Form1->Gauge1->Progress = 0; Form1->Gauge2->Progress = 0; SearchFin = true; MessageBox(NULL,"Fertig Katalog erfolgreich erstellt","Fertig",MB_OK); } } Katalog.close(); /* ifstream test; test.open("C:\\Kat.katalog"); std::string test2; std::getline(test,test2); MessageBox(NULL,test2.c_str(),"Debug Mode",MB_OK); */ }
Nun damit kann ich wenigstens schon mal bis zu einem Unterordner katalogisieren.
Ich mache Fortschritte, auch wenn ich hier keine Rekursion benutzt haben
und FindNext könnte auch hilfreich sein, ich bau das mal ein.EDIT: bitte sagt nix über GetFileExtansion
-
SB ist eine Statusbar! hatte ich wohl vergessen anzugeben.
Ein Stack- Overflow ist bei mir auch über >10 Ebenen noch nicht passiert???
Gruss
frank
-
Ja ?
Könntest du evtl das Projekt irgendwo uploaden ?
Solangsam verliere ich wirklich die Gedult.
mit folgendem Programm geht es nurbis zu einem bestimmten Komplexitätsgrad.
(mehre unterordner in mehreren unterordner ist zu viel)
Ich poste es einfach mal://--------------------------------------------------------------------------- #include <vcl.h> #include <string> #include <sstream> #pragma hdrstop #include "Katalogia.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma link "DirOutln" #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- void TForm1::READ(void) { FLB->Directory = DLB->Directory; RICH->Lines = FLB->Items; // ShowMessage(RICH->Text.c_str()); KomponentenNamen += RICH->Text.c_str(); } void TForm1::Child(String Dir, int Childcount) // beide Parameter nicht mehr in Gebrauch { DLB->Directory = Dir.c_str(); if (readmain == 0) { readmain = 1; READ(); } DLB->ItemIndex++; DLB->OpenCurrent(); FLB->Directory = DLB->Directory; READ(); int Child_Of_Child = DLB->Items->Count - (DLB->ItemIndex+1); Childs_have_been_read++; if (Child_Of_Child == 1) { DLB->ItemIndex++; Child(DLB->Directory, Child_Of_Child); } else if (Child_Of_Child > 1) // Ich unterscheide zwischen der Unterordnerzahl { Sub_Child = Childs_have_been_read; DLB->ItemIndex++; Multi_Child(DLB->Directory); } if (Child_Of_Child == 0) { int ReadChilds = 0; while (ReadChilds < Childs_have_been_read) { ReadChilds++; DLB->ItemIndex--; } DLB->OpenCurrent(); Childs_have_been_read = 0; } } void TForm1::Suchen(void) // Primärer Algorithmus { int Childreen = DLB->Items->Count - (DLB->ItemIndex); DESTICHILDCOUNT = Childreen; int i = 1; DESTINATION = DLB->Directory.c_str(); int one = 0; Sub_Child = 0; while (i < Childreen) { i++; Childs_have_been_read = 0; Current_Child++; Parent = DLB->Directory.c_str(); Child(DLB->Directory, Childs_have_been_read); int x = 0; while (x < Current_Child) { x++; DLB->ItemIndex++; } } } __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { readmain = 0; } //--------------------------------------------------------------------------- void __fastcall TForm1::SpeedButton1Click(TObject *Sender) // Beginnnt hier { DOUT->Update(); RICH->Text = LEER->Text; LB->Items = LEER->Lines; DLB->Directory = DOUT->Directory; DESTICHILDCOUNT = 0; Current_Child = 0; // SCHLEIFE ! // ShowMessage("PAUSE"); Suchen(); RICH->Text = KomponentenNamen.c_str(); LB->Items = RICH->Lines; } //--------------------------------------------------------------------------- void __fastcall TForm1::DOUTChange(TObject *Sender) { DLB->Directory = DOUT->Directory; } //--------------------------------------------------------------------------- void TForm1::Multi_Child(String CHDIR2) { int i = 1; // DLB->Directory = CHDIR2; int Childreen = DLB->Items->Count - (DLB->ItemIndex); std::string go_back = DLB->Directory.c_str(); while (i < Childreen) { Childreen = DLB->Items->Count - (DLB->ItemIndex); ShowMessage(IntToStr(Childreen).c_str()); i++; DLB->OpenCurrent(); Childs_have_been_read--; Child(DLB->Directory, Childreen); std::stringstream RCtoI; RCtoI.clear(); RCtoI << Childreen; RCtoI << " und "; RCtoI << i-1; ShowMessage(RCtoI.str().c_str()); int ReadChilds = 0; while (ReadChilds < i-1) { ReadChilds++; DLB->ItemIndex--; } DLB->OpenCurrent(); int x = 0; while (x < i) { x++; DLB->ItemIndex++; } } DLB->Directory = go_back.c_str(); }
Gibt es nicht irgendwo was Fertiges ? Ich habs langsam Satt, ich kann so tiefgründig nicht denken (Kein Kommentar).
Wenn ich bei geringer Komplexität beginne hab ich nacher ein Problem weil es nicht auf höere Komplexität aufstufbar ist.
Wenn ich gleich volle Kanne ran gehe, blicke ich nach 20 min nicht mehr durch meinen eigenen Code durch.Ach und wenn eine Funktion mir localen variablen in sich selbst aufrufe und gegeneinander, werden die Variablen dann neu angelegt oder überschrieben ?
(hier Child und Multi_Child ineinander verzweigt) Oder muss ich arrays anlegen ?Aber so langsam machts mir die lust kaputt und ich hör damit lieber auf und hoffe auf ein Wunder :p
-
Kannst Du Projekte vom BCB 4.0 problemlos einlesen?
Dann kann ich Dir das Projekt mailen.Schicke einfach eine Mail an die Adresse mit "DerAltenburger..." - die genaue Adresse steht auf meiner HP.
Gruss
Frank
-
Hallo,
ich weis nicht, ob das Thema nach aller der langen Zeit noch aktuell ist, aber auch ich möchte einen Code Schreiben, der eine Festplatte Katalogisiert.
Ich steige gerade in C ein und werde auf C++ weiter aufbauen.
Mal sehen, ob das ganze auch schon ab C lösbar ist.Mike
-
Ja sicherlich!
Momentan mache ich das Ganze aber schon etwas anders, als hier beschrieben.
Ich mache das momentan so (möglicherweise nicht so effizient, aber auch möglich):- 2 Listen anlegen (eine für Ordner und eine für Dateien)
- Das Anfangsverzeichnis der Ordnerliste hinzufügen
- Odernerliste durcharbeiten- Erstes Verzeichnis als aktuelles übernehmen und aus Liste entfernen (oder Index der Liste weitersetzen, wenn man die Verzeichnisse behalten will)
- Nach Verzeichnissen im aktuellen Verzeichnis suchen und Dateiliste hinzufügen
- Wiederholen bis Ordnelist leer (oder Index = Listengröße)- Bedarfsweise die Listen sortieren.
PS: Siehe Signatur 2. Teil :p