Stehe gerade etwas auf dem Schlauch. Ich muss mit einem C-Programmm eine mehrstufige Verzeichnisstruktur nach einem gewissen Dateityp (z.B. *.txt) durchsuchen. Hat dazu ev. jemand einen Schnipsel Beispielcode oder einen Link ? THX, interrupt
Welches Betriebssystem? Warum C? Jede moderne Scriptsprache macht das einfacher.
1 | char *pattern = "*.txt"; |
2 | DirRef dir = getDirRef(); |
3 | PathRef path; |
4 | int i; |
5 | |
6 | for(i=0; path=findFile(dir, pattern, i); i++) |
7 | {
|
8 | }
|
mit findFile als Funktion, die einen kompletten Pfad auf das erste, zweite, ... File mit dem Pattern zurück liefert. Beachte das = (nicht ==) im for. Ansonsten vielleicht schreiben, welche Strukturen und Funktionen Du stattdessn so hasst.
interrupt schrieb: > Ich muss mit einem C-Programmm eine mehrstufige Verzeichnisstruktur nach > einem gewissen Dateityp (z.B. *.txt) durchsuchen. > Hat dazu ev. jemand einen Schnipsel Beispielcode oder einen Link ? Ja: https://ftp.gnu.org/gnu/findutils/
Musst du Rekursiv machen. Also die selbe Routine immer wieder selbst aufrufen. Mit einen anderen Parameter. Du brauchst dazu 2 SUB-Routinen. Die erste liest den Ordner, die 2 die Files darin (mit Filter) BEIDE werden von einer Hauptroutine als SUB aufgerufen. Diese VB-Routine sucht alle Order im Angegeben Pfad. Private Sub SucheAlleOrdner(ByVal Pfad As String) Dim AlleOrdner() As String 'anz_pfad = 0 x = 0 AlleOrdner = Directory.GetDirectories(Pfad) ' da ist das File-Objekt gefragt For i As Integer = 0 To AlleOrdner.Length - 1 If AlleOrdner(i) <> Pfad Then AlleOrdner(i) = LCase(AlleOrdner(i)) hp_l_liste.Items.Add(AlleOrdner(i)) ' <- übergibt alle Ordner im Hauptorder an ein List-Element x = x + 1 my_pfad(x) = AlleOrdner(i) Call SucheAlleOrdner(AlleOrdner(i)) ' <- Der rekursive Aufruf !!! End If Next i End Sub Wenn du die hast, hast du ein Array mit allen Ordnern im Pfad. Dann musst du in einer 2 Routine die Files im Ordner aufrufen (absuchen) und damit machen was du willst halt. Wie du dem Code in C umschreibst weiß ich nicht, dürfte aber nicht so schwer sein. Kommt halt auf der FILE-Objekt an (ich benutze System.io in den Fall da.
Nachtrag: Du kannst auch Trick 17 benutzen. Shell aufrufen dann dir *.txt /s /b >txt-liste.txt Und dann die Liste mit Imput einlesen und verarbeiten. Ist für die schnelle faule einmalige Methode. Und das geht sogar einfach ohne Tools.
A. S. schrieb: > mit findFile als Funktion, die einen kompletten Pfad auf das erste, > zweite, ... File mit dem Pattern zurück liefert. Beachte das = (nicht > ==) im for. Vielen Dank, damit sollte ich weiter kommen, werde ich dann gleich mal testen. Betriebssystem ist Windows 10. Der Code sollte aber am besten betriebssystemunabhängig sein. Es soll ein bestehendes C-Programm um die Funktion erweitert werden.
Vielleicht kannst du dieses Beispiel für deine Zwecke anpassen. procDir wird vom Hauptprogramm aufgerufen und ruft sich für Unterverzeichnisse selbst rekursiv auf. procFile wird für reguläre Dateien aufgerufen, prüft die Endung, wenn nicht die Richtige (hier: pdf) beendet es sich, ansonsten wird hier die Datei umbenannt, indem eine Zeitstempel vor den alten Namen vorgesetzt wird. Gesamt 75 Zeilen Code.
interrupt schrieb: > > Der Code sollte aber am besten betriebssystemunabhängig sein. > Es soll ein bestehendes C-Programm um die Funktion erweitert werden. Komplett OS unabhängig? Das ist dann aber schon eine ganz andere Nummer - denn das würde ja bedeuten, auf OS-basierte Librariers zu verzichten - und nicht wirklich realisierbar!
Walter K. schrieb: > Komplett OS unabhängig? Das ist dann aber schon eine ganz andere Nummer > - denn das würde ja bedeuten, auf OS-basierte Librariers zu verzichten - > und nicht wirklich realisierbar! Hängt davon ab, die der Compiler die Bibliotheksfunktionen in OS-API Aufrufe umsetzt. Mein Beispiel von oben, sieht zwar erstmal nach Unix aus, wenn es aber mit MinGw (gcc für Windows) übersetzt wird, funktioniert es sogar so wie es das steht, mit dem Pfadtrenner '/' in Zeile 55.
interrupt schrieb: > > Der Code sollte aber am besten betriebssystemunabhängig sein. > Es soll ein bestehendes C-Programm um die Funktion erweitert werden. Halte ich für fast unmöglich. Allein das Thema RECHTE-Verwaltung zum Zugriff auf Ordner ist ne Geschichte für sich. Selbst wenn man "NUR" Windows + Linux nimmt rennt man schon gewaltig gegen eine Wand. Davon abgesehen, basieren solche Routinen auf Zugriffe das (jeweiligen) File-System. Ich habe in meinen VB-Code das File-System angeben weil ich selbst da, mehre Systeme zu Verfügung habe. Also schlicht und ergreifend VERGISS ES .
Ingo W. schrieb: > funktioniert es sogar so wie > es das steht, mit dem Pfadtrenner '/' i Das kann Windows schon lange.
> Das kann Windows schon lange.
Es kann immer noch keinen Kaffee kochen oder einen Ball holen.
Cartman schrieb: > Es kann immer noch keinen Kaffee kochen oder einen Ball holen. NOCH Nicht. Das geht erst ab IoT 2.0 wenn die Smart-Watch die den Bio-Rhythmus , Plus / Herzschlag + EKG kontrolliert erlaubt, das die Kaffeemaschine gestartet werden darf, welches Windows dann automatisch macht. Ist übrigens inzwischen mit TOP-Kaffee-Vollautomaten der neusten Generation sogar per App möglich. Selbstverständlich geht dann automatisch ein Hinweis in die digitale Krankenakte das du dein Körper mit einer legalen Droge geschädigt hast. Worauf die Krankenkasse dein Beitrag um 10 % anhebt. Was den Ball holen angeht. Windows schickt via Wlan eine Nachricht an dein Pflegeroboter, den du hast, weil dein Körper durch den vielen Kaffee so geschädigt ist, das der Pfegeroboter dann dein Ball holt. ;)
Eine Erweiterung hin zu c++ mit std::filesystem ist keine Alternative?
Schlaumaier schrieb: >> Der Code sollte aber am besten betriebssystemunabhängig sein. >> Es soll ein bestehendes C-Programm um die Funktion erweitert werden. > > Halte ich für fast unmöglich. In Standard-C++ gibt's das. Wobei es da auch gewisse Fallstricke gibt. Lustigerweise dann aber eher sowas unerwartetes wie der verwendete String-Typ. std::filesystem::path nutzt als String-Typ unter Linux std::string, unter Windows stattdessen std::wstring. > Allein das Thema RECHTE-Verwaltung zum Zugriff auf Ordner ist ne > Geschichte für sich. Da muss man nix "verwalten". Einfach öffnen und schauen, ob's klappt oder nicht.
Ingo W. schrieb: > procDir wird vom Hauptprogramm aufgerufen und ruft sich für > Unterverzeichnisse selbst rekursiv auf. > procFile wird für reguläre Dateien aufgerufen, prüft die Endung, wenn > nicht die Richtige (hier: pdf) beendet es sich, ansonsten wird hier die > Datei umbenannt, indem eine Zeitstempel vor den alten Namen vorgesetzt > wird. > Gesamt 75 Zeilen Code. Super, vielen Dank ! Das Programm ist compiliert und funktioniert. Ich verwende den MINGW64-Compiler mit Eclipse. "st_mtim" musste ich in "st_mtime" ändern und Zeile 63 musste von "procFile(root, d->d_name, sb.st_mtime.tv_sec);" in "procFile(root, d->d_name, sb.st_mtime);" geändert werden.
Schlaumaier schrieb: > VERGISS ES . Ehrlich? Du kapitulierst schon wenn es darum geht einen Verzeichnisbaum nach Text-Dateien zu durchsuchen?
Ingo W. schrieb: > Vielleicht kannst du dieses Beispiel für deine Zwecke anpassen. > > procDir wird vom Hauptprogramm aufgerufen und ruft sich für > Unterverzeichnisse selbst rekursiv auf. > procFile wird für reguläre Dateien aufgerufen, prüft die Endung, wenn > nicht die Richtige (hier: pdf) beendet es sich, ansonsten wird hier die > Datei umbenannt, indem eine Zeitstempel vor den alten Namen vorgesetzt > wird. > Gesamt 75 Zeilen Code. Ich habe Deinen Code jetzt so angepasst, dass er eine Verzeichnisstruktur durchsucht und darin enthaltene Textdateien (*.txt) anzeigt. Datzu habe ich testweise einen vierstufigen Verzeichnisbaum angelegt und darin kleine Textdateien gespeichert. Der Aufbau ist im Diagramm in der Grafik ersichtlich, "dirx" steht dabei für Verzeichnisse, "textx" für Textdateien. Das Programm funktioniert grundsätzlich, es findet und zeigt alle vorhandenen Verzeichnisse und Dateien an. Allerdings ist das Verhalten doch recht verwunderlich, weil die Anzeige der Verzeichnisse und der darin enthaltenen Dateien nicht synchronisiert ist. Bei den Verzeichnissen (blaue Pfeile) ist der Ablauf logisch nachvollziehbar, er beginnt ganz oben am Einstiegsverzeichnis "data" und arbeitet sich dann bis ganz nach unten durch, dann springt er auf benachbarte Verzeichnisäste. Bei den Dateien (rote Pfeile) beginnt die Anzeige aber erst, wenn das Programm schon ganz unten in der Verzeichnishierachie angekommen ist (Punkt "dir4.1") und danach arbeitet sich die Dateianzeige recht kreativ weiter durch, bis auch alle Dateien angezeigt wurden, allerdings in einer anderen Reihenfolge als die Verzeichnisse. Das Problem ist also, dass man im Programmablauf die gefundenen Dateien so nicht direkt den Verzechnissen zurordnen kann, in denen sie enthalten sind. Hat jemand eine Erklärung für die Logik dieses Programmablaufen ?
pointer schrieb: > Hat jemand eine Erklärung für die Logik dieses Programmablaufen ? Dein Programm bearbeitet offensichtlich in jedem Verzeichnisknoten erst die Unterverzeichnisse und dann die regulären Dateien. Wenn du das als unlogisch empfindest, kannst du diese Reihenfolge ja umdrehen (also erst die regulären Dateien anzeigen und dann erst in die Unterverzeichnisse absteigen).
Yalu X. schrieb: > Dein Programm bearbeitet offensichtlich in jedem Verzeichnisknoten erst > die Unterverzeichnisse und dann die regulären Dateien. Wenn du das als > unlogisch empfindest, kannst du diese Reihenfolge ja umdrehen (also erst > die regulären Dateien anzeigen und dann erst in die Unterverzeichnisse > absteigen). Na ja, bei den ersten drei Verzeichnisknoten (dir1, dir2.1, dir3.1) bearbeitet das Programm die darin enthaltenen Dateien ja gar nicht (wobei sie ja erst mal gar nicht bearbeitet, sondern nur angezeigt werden sollen), und erst beim vierten Knoten (dir4.1) wird die darin enthaltene Textdatei angezeigt. Die Anzeige der in den Knoten darüber enthaltenen Dateien wird dann nachgeholt, wobei das nicht synchron mit der Durchsuchung der Verzeichnisse abläuft. Mir erschliesst sich die Logik nicht noch so ganz.
In dem Beispielprogramm gibt es keinerlei Sortierung, die Objekte (Dateien, Verzeichnisse) werden in der Reihenfolge abgearbeitet, in der die "readdir"-Funktion sie liefert. Diese Funktion muss die Daten aus einem entsprechenden Betriebssystem-API beziehen. Unter Linux ist das die rohe Reihenfolge in der die Einträge im Verzeichnis stehen (sie im jungfräulichen Verzeichnis angelegt wurden). Unter Windows habe ich es so in Erinnerung, dass sie hier in alphabetischer Reihenfolge geliefert werden. Wenn du eine bestimmte Reihenfolge haben möchtest, müsstest du die Daten des Verzeichnisses erst sortieren und dann verarbeiten. Da man vorher schlecht weiß, wie viele Verzeichniseinträge kommen, mache ich so etwas gern mit verketteten Listen.
> strcpy(st,cp);
Mach da mal eine Längenbeschränkung rein, eignet sich sonst für Stack
Hacks.
Weil ich das auch selbst gut gebrauchen kann, habe ich das Gerippe jetzt mal so umgearbeitet, dass das gelesene Verzeichnis vor der Abarbeitung erst sortiert wird (Verzeichnisse alphabetisch aufsteigend, dann Dateien alphabetisch aufsteigend). Da es mir um das Umbenennen von Dateien geht, wird der "procFile"-Funktion, in einer Struktur, das Verzeichnis und der Dateiname getrennt übergeben, damit für den neuen Dateinamen nicht das Verzeichnis wieder extrahiert werden muss. Markus L. schrieb: > Mach da mal eine Längenbeschränkung rein, eignet sich sonst für Stack > Hacks. Die Puffer werden mit einer Länge von PATH_MAX angelegt. Hier gehe ich mal blauäugig davon aus, dass das lokale Dateisystem nicht mehr hergibt. Da dies hier eigentlich gelesen wird, sollte der Einfluss von außen begrenzt sein.
Ingo W. schrieb: > Weil ich das auch selbst gut gebrauchen kann, habe ich das Gerippe jetzt > mal so umgearbeitet, dass das gelesene Verzeichnis vor der Abarbeitung > erst sortiert wird Mein Compiler (mingw64) in Exlipse meldet eine Warnung und einen Fehler : 23:32:59 **** Rebuild of configuration Debug for project mp_test_dirs_files **** Info: Internal Builder is used for build g++ -O0 -g3 -Wall -c -fmessage-length=0 -o main.o "..\\main.cpp" ..\main.cpp: In function 'void procDir(char*)': ..\main.cpp:40:9: warning: suggest parentheses around assignment used as truth value [-Wparentheses] while(d=readdir(di)){ ~^~~~~~~~~~~~ ..\main.cpp:45:15: error: invalid conversion from 'void*' to 'set*' [-fpermissive] next=calloc(1,sizeof(set)); ~~~~~~^~~~~~~~~~~~~~~ 23:33:00 Build Failed. 1 errors, 1 warnings. (took 1s.103ms)
Mit "next = (set*) calloc(1, sizeof(set));" statt "next=calloc(1,sizeof(set));" in Zeile 45 klappt das Compilieren.
interrupt schrieb: > Mit > "next = (set*) calloc(1, sizeof(set));" > statt "next=calloc(1,sizeof(set));" > > in Zeile 45 klappt das Compilieren. Das deutet darauf hin, dass du den Code als C++ statt als C kompiliert hast. In C++ geht es nicht ohne den Cast. In C braucht man den nicht, und sollte weggelassen werden. Unnötiges Casten ist in C Code nicht gerne gesehen.
🐧 DPA 🐧 schrieb: > Das deutet darauf hin, dass du den Code als C++ statt als C kompiliert > hast. Darauf deutet auch das hin: interrupt schrieb: > g++ -O0 -g3 -Wall -c -fmessage-length=0 -o main.o "..\\main.cpp" > In C braucht man den nicht, > und sollte weggelassen werden. Unnötiges Casten ist in C Code nicht > gerne gesehen. Das Problem dabei ist, dass es an so einer Stelle einen Fehler verdecken kann.
Ingo W. schrieb: > Weil ich das auch selbst gut gebrauchen kann, habe ich das Gerippe jetzt > mal so umgearbeitet, dass das gelesene Verzeichnis vor der Abarbeitung > erst sortiert wird (Verzeichnisse alphabetisch aufsteigend, dann Dateien > alphabetisch aufsteigend). Das Program funktioniert, aber die im Beitrag vom 12.02.2022 00:16 erwähnte und per Grafik visualisierte Asynchronität zwischen der Anzeige der Verzeichnisse und der darin enthaltenen Dateien besteht weiter. Ich habe das Urspungsprogramm vom Beitrag am 05.02.2022 13:37 jetzt mal in zwei Varianten so überarbeitet, dass die in den Verzeichnissen enthaltenen Dateien dann angezeigt werden, wenn sich das Programm auch in diesem Verzeichnissen befindet. Das erste Programm (main_A.cpp) verwendet dazu readdir(), FindFirstFile() und FindNextFile(). Das zweite Programm (main_B.cpp) nutzt readdir(),_findfirst() und _findnext(). Durchsucht wird der Verzeichnisbaum in .\data (gepackt in "data.7z") Der Aufruf des Programme erfolgt mit <programm.exe> ".\data" Der Code wurde mit mingw64 in Eclipse compiliert
interrupt schrieb: > Das Program funktioniert Meine Güte... Wieviele Stunden hast Du gebraucht um die ganzen Code-Fetzen zusammen zu googeln? Das Programm funktioniert übrigens nicht. Es ist Schrott. Du hast einen kapitalen Denkfehler. Du brauchst z.B. nur opendir(), readdir(), stat() und closedir(). Stell Dir ein Verzeichnis wie eine Textdatei vor mit Zeilen. Jede Zeile ist ein Eintrag im Verzeichnis. Der Einträge bestehen aus dem "Datei"namen. Mit opendir() öffnest Du ein Verzeichnis. "Öffnen" bedeutet nicht ins Verzeichnis wechseln oder sonstwie irgendetwas. Sondern nur öffnen, so wie Du eine Datei zu lesen öffnen würdest. Du öffnest ein Telefonbuch (Kennt das hier noch jemand, also aus Papier?). Mit readdir() liest Du den nächsten Eintrag aus einem geöffneten Verzeichnis. Der Eintrag besteht u.a. aus dem Namen. Und nur dem Namen. Ohne Pfadangabe. Danach baust Du aus dem Verzeichnisnamen und Eintragsnamen den Pfad zu einer "Datei". Mit stat() schaust Du nach, was die "Datei" ist. Ist es eine echte Datei, oder ist es nur ein weiteres Verzeichnis? Mit closedir() schließt Du das Verzeichnis wieder. Das Betriebssystem dankt Dir dafür. Also, sieht der Code ungefähr so aus (Pseudocode):
1 | void processDir(dirName) |
2 | { |
3 | print("Untersuche Verzeichnis:" + dirName); |
4 | |
5 | dir = opendir(dirName); |
6 | |
7 | while ((entry = readdir(dir)) |
8 | { |
9 | if (entry.name != "." && entry.name != "..") |
10 | { |
11 | path = dirName + "\" + entry.name; |
12 | |
13 | info = stat(path); |
14 | |
15 | if (info.type == DIRECTORY) |
16 | { |
17 | print("Verzeichnis gefunden:" + path); |
18 | processDir(path); |
19 | } |
20 | else |
21 | { |
22 | print("Datei gefunden:" + path); |
23 | } |
24 | } |
25 | } |
26 | |
27 | closedir(dir); |
28 | } |
Einer schrieb: > trivialer Quuatsch ja und, glaubst du wirklich, du erzählst damit etwas neues ? Fakt ist allerdings, dass wie bereits geschrieben, die Verzeichnisse und die darin enthaltenen Dateien mit readdir() nicht synchron ausgegeben werden. Begriffsstutzige wie Du können sich dazu auch das Diagramm vom 12.02.2022 00:16 anshen. Darin sieht man z.B., dass die Datei im obersten Verzeichnis erst augegeben wird, wenn mit readdir() die ganze Verzeichnisstruktur rekursiv durchlaufen ist. Ich bevorzuge allerings die Ausgabe buzw. Berabreitung der in einem Verzeichnis enthaltenen Dateien genau dann, wenn sich das Programm auch in diesem Verz3eichnis befindet.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.