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
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 .
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. ;)
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.
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.
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)
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):
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.