Twitter und Facebook-Anbindung
X
Tweet Follow @twitterapi
!!! Anbindung an twitter und facebook öffnen !!!

Wenn Ihnen mein Online-Buch gefällt,
dann bedanken Sie sich doch mit einer kleinen Spende...

13.4 Durchsuchen von Verzeichnissen

13.4 Durchsuchen von Verzeichnissen

Bisher habe ich Ihnen zwar gezeigt, wie man auf Dateien zugreifen kann, aber nicht, wie man eine Datei findet. Genau darum geht es in diesem Unterkapitel. Bevor wir loslegen können, muss ich Ihnen ein paar Worte zur Windows API erzählen.

Zum Seitenanfang
Zum Inhaltsverzeichnis

13.4.2 Hinweise zu den Variablentypen der Windows API

13.4.2 Hinweise zu den Variablentypen der Windows API

Ein weiterer Stolperstein der Windows API ist, dass es sehr viele Typdefinitionen, also Aliasnamen, für bekannte Datentypen gibt und das diese auch oftmals verlangt, bzw. zurückgegeben werden. Dies wurde aber nicht aus reiner Schikane gemacht, sondern um eine Vereinheitlichung vorzunehmen. Ich hatte ja mal erwähnt, dass ein Integer früher nur zwei Byte groß war und heute meist vier Byte groß ist. Der durch Windows spezifizierte Datentyp "DWORD" steht für "double Word" und entspricht einem heutigen Integer. Früher wusste man durch das "double", dass der Datentyp größer war als ein Integer. Genauso tauchen Datentypen wie "LPCSTR" auf, was heißt "large pointer of const string", also ein heutiger "const char*". Sie fragen sich jetzt bestimmt wieder, warum "large pointer"? Die Begründung fällt wie eben aus. Pointer waren schon immer Integervariablen und da heute die Integer größer sind, sind auch die Pointer größer (streng genommen ist es anders herum, da man mehr Arbeitsspeicher adressieren können wollte). Es gibt noch unzählige andere Datentypen, aber wenn man schaut wo sie definiert sind, sieht man was dahinter steckt und man hat wieder die bisher bekannten Typen vor sich.

Zum Seitenanfang
Zum Inhaltsverzeichnis

13.4.4 Vorbemerkung zur Verzeichnissuche

13.4.4 Vorbemerkung zur Verzeichnissuche

Wie schon erwähnt, sind Verzeichnisse auch nur Dateien. Jene haben aber ein ganz bestimmtes Dateiattribut (Bitmaske). Des Weiteren bekommt man keine Information darüber, wie viele Verzeichnisse und/oder Dateien sich in einem Verzeichnis befinden. Möchte man dies wissen, muss man es wie gleich gezeigt durchlaufen und selber die gefundenen Einträge zählen.

Ein weiterer Irrglaube ist, dass man alle Einträge in alphabetischer Reihenfolge bekommt. Oftmals ist dem so, aber eine Garantie dafür gibt es nicht. Des Weiteren werden auch Dateien und Verzeichnisse gemischt ermittelt. Falls man also diese Angaben trennen möchte, muss man wieder selbst Hand anlegen.

Am wichtigsten jedoch ist, dass ein Durchsuchen viele Gemeinsamkeiten mit dem Öffnen und Schließen einer Datei hat. Deswegen ist es extrem wichtig, dass jede Suche mit einem speziellen Befehl wieder beendet wird. Andernfalls bekommt man mit diesem Verzeichnis so lange Probleme (gerade wenn man es löschen oder umbenennen will), bis Windows neu gestartet wurde.

Wenn ein Verzeichnis durchsucht wird, bekommt man meist zu Beginn zwei Einträge, die oft nicht benötigt werden. Es sind die Einträge "." und "..", welche für DOS eine große Rolle spielen. Der einzelne Punkt steht für das aktuelle Verzeichnis und der doppelte für das übergeordnete Verzeichnis. Ggf. müssen Sie diese zwei Einträge also ausfiltern.

Zum Seitenanfang
Zum Inhaltsverzeichnis

13.4.5 Implementierung der Dateisuche

13.4.5 Implementierung der Dateisuche

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
					
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

// ...

WIN32_FIND_DATAA	sFileInfo;
HANDLE			hFileHandle	= FindFirstFileA("C:\\*.*", &sFileInfo);
bool			bGoOn		= hFileHandle != INVALID_HANDLE_VALUE;

// Solange Einträge gefunden werden
while (bGoOn) {
	// Wenn ein Verzeichnis gefunden wurde
	if (sFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
		// Nur relevante Verzeichnisse
		if ((strcmp(sFileInfo.cFileName, ".") != 0) &&
		    (strcmp(sFileInfo.cFileName, "..") != 0)) {

			printf("Verzeichnis:  %s\n", sFileInfo.cFileName);
		} // end of if
	} else {
		printf("Datei:        %s\n", sFileInfo.cFileName);
	} // end of if

	bGoOn				= FindNextFileA(hFileHandle, &sFileInfo);
} // end of while

FindClose(hFileHandle);
					

Wie Sie sehen, gibt es drei wichtige Funktionen, nämlich "FindFirstFileA", "FindNextFileA" und "FindClose". Erstere Startet die Suche und dort gibt man auch das Verzeichnis an, welches durchsucht werden soll. Wenn man kein Pfad angibt, wird das Verzeichnis durchsucht, in welchem das Programm liegt. Das "*.*" bedeutet, dass alle Einträge beachtet werden sollen. Würde man z.B. "*.jpg" angeben, würden alle JPEG Dateien (Bilder) gefunden werden, wobei die Groß - und Kleinschreibung nicht berücksichtigt wird.

Zum Seitenanfang
Zum Inhaltsverzeichnis

13.4.6 Auflisten aller vorhandener Laufwerke

13.4.6 Auflisten aller vorhandener Laufwerke

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
					
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

// ...

char* pstrDrive		= new char[4];
pstrDrive[1]		= ':';
pstrDrive[2]		= '\\';
pstrDrive[3]		= '\0';		// Terminierungszeichen

// Durchlaufe alle möglichen Laufwerke
for (char cDrive = 'A'; cDrive <= 'Z'; cDrive++) {
	pstrDrive[0]	= cDrive;

	// Je nachdem, um welches Laufwerk es sich handelt
	switch (GetDriveTypeA(pstrDrive)) {
		case DRIVE_REMOVABLE:
			printf("%c: - Auswerfbares Laufwerk\n", cDrive);
			break;
		case DRIVE_FIXED:
			printf("%c: - Festplatte\n", cDrive);
			break;
		case DRIVE_REMOTE:
			printf("%c: - Netzlaufwerk\n", cDrive);
			break;
		case DRIVE_CDROM:
			printf("%c: - Optisches Laufwerk\n", cDrive);
			break;
	} // end of switch
} // end of for

delete [] pstrDrive;
					

Da die Funktion "GetDriveTypeA" Angaben der Art "C:\" benötigt, muss ich mir zunächst in den Zeilen 8 bis 10 und 14, diese Pfadangabe zusammen bauen. Der Rest ist ganz einfach. Man klappert alle möglichen Laufwerksbuchstaben von A bis Z ab und schaut, welche Informationen man bekommt. Hierbei sei aber noch erwähnt, dass hier alle Laufwerke aufgelistet werden, egal ob z.B. in einem CD-ROM Laufwerk eine CD liegt oder nicht. Des Weiteren gilt z beachten, dass die Laufwerkstypen etwas schwammig sind. "DRIVE_CDROM" heißt auch DVD oder BluRay und "DRIVE_REMOVABLE" kann für einen USB-Stick (wird allerdings nur erkannt, wenn er am Rechner angeschlossen ist) oder ein Kartenleser stehen.

Die Windows API stellt noch weitere nützliche Funktionen bereit (Freier Speicherplatz oder Pfadangaben zum Windowsverzeichnis oder dem Benutzerverzeichnis), auf welche ich jetzt nicht im Detail eingehen möchte. Schauen Sie also ins MSDN und erkunden Sie die anderen Möglichkeiten.

Zum Seitenanfang
Zum Inhaltsverzeichnis

13.4.2 Bitmasken

13.4.2 Bitmasken

Ein weiterer Aspekt ist, dass oft Masken übergeben werden sollen. Es handelt sich hierbei wieder um einfache Integer, welche aber durch Bitoperationen mehrere Werte bzw. Flags aufnehmen können. Ich hatte bereits über Bitfelder gesprochen, wobei ich aber keine richtigen Bitfelder gezeigt habe, sondern einen neuen Mechanismus gezeigt habe, welcher wesentlich komfortabler war. Jetzt kommen wir aber nicht mehr umher, dies nachzuholen.

Die große Frage also lautet, wie kann ich jedes der 32 Bit eines Integers einzeln abfragen und setzen? Die Antwort ist ganz einfach. Zum Lesen verwendet man eine AND Operation, zum Setzen eine OR Operation und zum Entfernen eine XOR Operation. Wie und warum das Funktioniert, sollen folgende Grafiken zeigen.

Bitweise Verknüpfung mit AND

Wie Sie sehen können, kann man mit dem "&" Operator eine bitweise Verknüpfung machen und nur wenn der kleinere Wert im größeren enthalten ist, erhält man als Ergebnis den kleineren Wert. Ansonsten bekommt man einen anderen. Da ein Flag meistens nur durch ein oder maximal 2 benachbarte Bits signalisiert wird, kann man getrost davon ausgehen, dass das Ergebnis der Operation 0 ist, wenn das Flag nicht enthalten ist. Beachten Sie, dass dieses einzelne "&" an dieser Stelle nichts mit dem Referenzierungsoperator zu tun hat und verwechseln Sie es bitte auch nicht mit dem Verknüpfungsoperator "&&", welcher bei Bedingungen zum Einsatz kommt.

Bitweise Verknüpfung mit OR

Den Operator "|" müssen Sie sich wie ein intelligentes Plus vorstellen. Sie können damit ein Flag zu einer Maske dazu addieren und falls es schon enthalten ist, stört das nicht weiter.

Bitweise Verknüpfung mit XOR

Mit dem "^" Operator können Sie wieder Flags von einer Maske entfernen, aber wie Sie sehen, müssen Sie aufpassen. Dieser Operator verhält sich wie ein Plus und ein Minus. Falls Sie also ein Flag entfernen wollen, was gar nicht gesetzt war, setzen Sie es. Bevor Sie diese Operation anwenden, müssen sie also mit "&" prüfen, ob es enthalten ist. Und falls Sie sich wundern, dass ich zu Beginn behauptet hatte, dass es in C kein XOR gibt, dann weiße ich Sie nochmal auf den Unterschied zwischen einem Bitoperator und einem Verknüpfungsoperator hin. In einer Bedingung kann man zwei Ausdrücke nicht mit XOR koppeln, aber bei Bitoperationen steht einem ein XOR zur Verfügung.

Zum Seitenanfang
Zum Inhaltsverzeichnis

13.4.1 Funktionshinweise zur Windows API

13.4.1 Funktionshinweise zur Windows API

Zunächst einmal sollten Sie an dieser Stelle nicht zurück schrecken, denn wenn man sich ein paar dieser Funktionen anschaut, wird man ein wenig verunsichert. Ich möchte hier ein wenig Licht ins Dunkle bringen.

Als erstes muss man bedenken, dass die heutigen Windowsversionen weitestgehend abwärtskompatibel sind. Das heißt jetzt nicht unbedingt, dass man unter Windows 7 noch ein Windows 95 Programm ausführen kann. Vielmehr meine ich den internen Aufbau. Das hat zur Folge, dass es viele Funktionen in mindestens zwei Versionen gibt. Einmal die Klassische und dann die Moderne. Meistens macht sich dies dadurch bemerkbar, dass man zum einen ganz normale Strings übergibt bzw. zurück bekommt und das andere Mal bekommt man "WideStrings" im Unicode 16 Format. Letztere benötigen nicht nur ein Byte pro Zeichen, sondern zwei (damit kann man z.B. auch deutsche Umlaute und kyrillische Buchstaben darstellen). Dazu kommt noch, dass es meistens noch eine allgemeine Version der Funktion gibt, welche im Hintergrund nur eine der anderen beiden anspricht (je nach Systemvoreinstellung). Hier mal ein Beispiel.

Da der Umgang mit den "WideChars" etwas gewöhnungsbedürftig ist (zumal man für alle bekannten Stringfunktionen äquivalente andere aufrufen muss, welche oft mit "w" oder "_t" beginnen), werde ich mich ausschließlich auf die ASCII Funktionen beschränken. Falls Sie jetzt also mal eine Funktion mit einem großen A oder W am Ende sehen, wissen Sie jetzt, was dies zu bedeuten hat.

Zum Seitenanfang
Zum Inhaltsverzeichnis

© Copyright by Thomas Weiß, 2009 - 2012