ein Kapitel zurück                                           ein Kapitel weiter

Die Struktur DIR, eine interne Struktur, wird von allen 4 Funktionen, die wir in diesem Kapitel lernen, benutzt um Informationen über das zu lesende Directory zu erhalten und diese untereinander auszutauschen. Zuerst die Funktion opendir...

#include <sys/types.h>
#include <dirent.h>

DIR *opendir(const char *dirname);

Die Funktion opendir gibt bei Fehler NULL zurück. Ansonsten gibt die Funktion den DIR-Zeiger. Hierzu ein kurzes Beispiel der Anwendung...

DIR *dir;
if((dir=opendir(dirname)) != NULL)

Bei Erfolg ist nun das Directory mit dem Namen dirname geöffnet. Den DIR-Zeiger, in diesem Beispiel dir, benötigen wir für die restlichen 3 Funktionen.

Kommen wir gleich zur nächsten Funktion readdir. Hierzu der Syntax...

#include <sys/types.h>
#include <dirent.h>

struct dirent *readdir(DIR *dir);

Mit dieser Funktion Lesen wir aus dem Verzeichnis das wir zuvor mit opendir geöffnet haben Schrittweise aus. Bei einem Fehler gibt diese Funktion NULL zurück. Ansonsten einen Zeiger vom Typ struct dirent, der folgendermaßen aussieht....

struct dirent {
               ino_t d_ino;      //i-node Nr. (nicht bei Dos)
               char d_name[x+1]; //Dateiname mit abschl. '\0'
              };
              

In der Praxis sieht das dann wieder etwa so aus...

DIR *dir;
struct dirent *dirzeiger;
if((dir=opendir(dirname)) != NULL)
.........................................
while((dirzeiger=readdir(dir)) != NULL)
    printf("%s\n",(*dirzeiger).d_name);
    

Hiermit würde mit readdir der ganze Inhalt eines Verzeichnisses ausgegeben werden.

Mit der Funktion rewinddir setzten sie den Lesezeiger wieder an den Anfang der Namenliste des Verzeichnises. Der Syntax von rewinddir...

#include <sys/types.h>
#include <dirent.h>

void rewinddir(DIR *dir);

Jetzt nur noch schnell zu closedir. Wie der Name schon sagt, mit dieser Funktion wird das Verzeichnis geschlossen und beendet. Bei Erfolg gibt diese Funktion 0 zurück und bei Fehler -1. Hier der Syntax...

#include <sys/types.h>
#inlcude <dirent.h>

int closedir(DIR *dir);

Nun möchte ich ein ausführbares Beispiel mit allen 4 Funktionen demonstrieren...

/*Download:dir1.c*/
#include <sys/types.h> #include <dirent.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { DIR *dir; struct dirent *dirzeiger; if(argc != 2) { fprintf(stderr,"Benutzung : %s Directory\n",argv[0]); exit (1); } /*Wir oeffnen ein Verzeichnis mit opendir*/ if((dir=opendir(argv[1])) == NULL) { fprintf(stderr,"Fehler bei opendir.....\n"); exit (1); } /*Wir lesen aus unserem Verzeichnis mit readdir*/ while((dirzeiger=readdir(dir)) != NULL) printf("%s\n",(*dirzeiger).d_name); /*Wir setzten den "Lesezeiger" dir wieder an den Anfang*/ rewinddir(dir); /*Wir lesen erneut das Verzeichnis*/ while((dirzeiger=readdir(dir)) != NULL) printf("%s\n",(*dirzeiger).d_name); /*Wir beenden und schließen unseren "Lesezeiger" dir*/ if(closedir(dir) == -1) printf("Fehler beim Schließen von %s\n",argv[1]); return 0; }

Mit diesem Programm geben sie 2x das Inhaltsverzeichnis eines Directorys aus. Jetzt wollen wir mal ein etwas längeres und brauchbares Beispiel programmieren. Nehmen sie sich für das Programm ausreichend Zeit es zu studieren. Ich habe es reichlich Kommentiert. Dies Programm soll in einem Verzeichnis eine bestimmte Datei suchen und diese dann Ausgeben inklusive Pfad. Zusätzlich wird noch der ganze Verzeichnisbaum diese Verzeichnisses ausgegeben. Das Programm führen sie etwa so aus...

dir2 /home text.txt

Somit sucht das Programm mit dem Namen dir2 das ganze Verzeichnis ab home mit allen Unterverzeichnissen nach der Datei text.txt. Anschließend können sie wenn sie wollen in das Verzeichnis wechseln in dem sie die Datei gefunden haben....

/*Download:dir2.c*/
/*Aus dem Buch C-Kompaktreferenz von Helmut Herold*/ /*Bitte passen sie die Headerdateien Ihrem System an*/ #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> #include <dirent.h> #include <sys/types.h> #include <sys/stat.h> #include <sys\stat.h> #include <unistd.h> #include <dir.h> /*Konstanten------------------------------------------*/ #define NODIRECT 1 /*Datei ist kein Directory*/ #define DIRECTOR 2 /*Datei ist ein Directory*/ #define NOREADDIRCT 3 /*Nichtlesbares Verzeichnis*/ #define NOSTAT 4 /*Datei auf die stat erfolglos ist*/ #define MAX 1000 #define FEHLER(string) {fprintf(stderr,"%s\n",(string));exit(1);} /*-----------------------------------------------------------*/ /*Typendefinition------------------------------------------*/ typedef int AUSWERTUNG(const char *, const struct stat *,int); static AUSWERTUNG auswertung; /*---------------------------------------------------------*/ /*Globale Variablen-----------*/ static char pfadname[MAX]; static char suchstring[MAX]; static char gefundenin[MAX]; static int tiefe; static long int dateizahl; int gefunden=0; /*----------------------------*/ /*Funktionsdeklarationen------------------*/ static int ebene_tiefer(char *,AUSWERTUNG *); static int pfad_behandeln(AUSWERTUNG *); /*-------------------------------------------*/ /*Funktionen==============================================*/ /*Baum um eine ebene tiefer absteigen---------------------*/ int ebene_tiefer(char *pfad, AUSWERTUNG *funktion) { char dirname[MAX]; int n; /*Wir ermitteln den Working - Directory - Namen und schreiben diesen an die Adresse von dirname*/ if(getcwd(dirname,MAX) == NULL) FEHLER("Konnte den Namen des Working Directorys nicht ermitteln"); /*Wir wechseln in den Angegebenen Pfad*/ if(chdir(pfad) == -1) FEHLER("Konnte nicht in den gewuenschten Pfad wechseln") /*Wir ermitteln den Absoluten Pfadnamen und schreiben diesen an die Adresse von pfadname*/ if(getcwd(pfadname,MAX) == NULL) FEHLER("Konnte den Absolut. Pfadnamen nicht ermitteln...") /*Wir wollen den aktuellen Pfad behandeln und schauen was sich so darin befindet*/ n=pfad_behandeln(funktion); printf("\n==== %ld ====\n",dateizahl); /*Wenn der ganze Directorybaum durchlaufen ist geht es wieder zurück zu unserem ursprünglichen Directory das wir am Anfang dieser Funktion mit getcwd ermittelt und an die Adresse von dirname übergeben haben*/ if(chdir(dirname) == -1) FEHLER("Kann nicht in das urspr. Directory zurueckwechseln") return(n); } /*----------------------------------------------------------*/ /*----------------------------------------------------------*/ /*Funktion zur Behandlung des Pfades. Diese Funktion wird in der Funktion ebene_tiefer(..) aufgerufen*/ static int pfad_behandeln(AUSWERTUNG *funktion) { struct stat attribut; struct dirent *name; DIR *dir; int n; char *zeiger; /*Wir wollen schauen ob unsere Globale Variable pfadname deren Inhalt wir in der Funktion ebene_tiefer() gegeben haben ein Directory ist oder nicht*/ if(stat(pfadname,&attribut) == -1) return(funktion(pfadname, &attribut, NOSTAT)); /*Fehler stat*/ /*Ist es ein Directory oder keines(==0) (S_IFDIR)?*/ if((attribut.st_mode & S_IFDIR) == 0) return(funktion(pfadname, &attribut, NODIRECT)); /*Kein Directory*/ /*Wenn wir bis hierhin gekommen sind liegt ein Directory vor*/ /*Ist das Directory überhaupt lesbar?(opendir)*/ if((dir = opendir(pfadname)) == NULL) { /*Nicht Lesbar*/ closedir(dir); return(funktion(pfadname, &attribut, NOREADDIRCT)); } /*Wir geben unseren Directorypfad aus*/ if((n=funktion(pfadname, &attribut, DIRECTOR)) !=0) return (n); /*Slash an den Pfadnamen hängen*/ zeiger=pfadname+strlen(pfadname); /*Zeiger zeigt auf das Ende von pfadname*/ *zeiger++ = '\\'; /*Slash hinhängen, bei Linux '/' */ *zeiger = '\0'; /*String terminieren*/ /*Wir lesen den Inhalt von pfadnamen aus (readdir) */ while((name=readdir(dir)) != NULL) {/*Falls es . und .. sind -> ignorieren*/ if(strcmp((*name).d_name,".") && strcmp((*name).d_name,"..")) { strcpy(zeiger,(*name).d_name); /*Dateiname nach dem Slash hängen*/ tiefe++; /*Bei der zu suchenden Datei ist auf Gross und Klein- schreibung zu achten.*/ if(strcmp((*name).d_name,suchstring) == 0) { gefunden=1; strcpy(gefundenin,pfadname); } /*Achtung - Jetzt kommt eine Rekursion. Ein Rekursion ruft eine Funktion immer wieder selbst auf bis die Abruchbedienung erfüllte ist*/ if(pfad_behandeln(funktion) != 0) /*Rekursion*/ { tiefe--; break; } tiefe--; } }//Ende while *(zeiger-1)= '\0'; if(closedir(dir)) FEHLER("Kann den erwuenschten Pfad nicht mehr schliessen") return(n); } /*-----------------------------------------------------------------*/ /*----------------------------------------------------------------*/ /*Funktion zur Auswertung und Ausgabe auf dem Bildschirm*/ static int auswertung(const char *pfad,const struct stat *zeiger,int dateityp) { static int erstemal=1; int i; dateizahl++; if(!erstemal) { for(i=1; i<=tiefe; i++) printf("%4c",' '); printf("----%s",strrchr(pfad,'\\')+1); } else { printf("%s",pfad); erstemal=0; } switch(dateityp) { case NODIRECT : if((*zeiger).st_mode & S_IFCHR) printf(" c\n"); else if((*zeiger).st_mode & S_IFREG) printf("\n"); break; case DIRECTOR : printf("\\\n"); break; case NOREADDIRCT : printf("\\-\n"); break; case NOSTAT : fprintf(stderr,"Fehler bei stat auf Datei %s\n",pfad); break; default : FEHLER("...Unbekannter Dateityp........exit") } return 0; } /*-------------------------------------------------------------------------*/ /*Ende der Funktionen======================================================*/ /*main - Funktion==========================================================*/ int main(int argc, char *argv[]) { char jn; char *z; if(argc != 3) { fprintf(stderr,"Benutzung %s Directory Datei\n",argv[0]); exit (1); } strcpy(suchstring,argv[2]); ebene_tiefer(argv[1], auswertung); if(gefunden==1) { z=gefundenin+strlen(gefundenin); while(*z-- != '\\'); *++z='\0'; printf("Datei gefunden in %s\n",gefundenin); printf("Wollen sie in das Verzeichnis wechseln (j/n) ? "); scanf("%c",&jn); if(jn=='j') chdir(gefundenin); } else printf("Konnte die Datei %s nicht finden\n",suchstring); return 0; } /*Ende Main und Ende Programm ==============================================*/

Lassen sie sich nicht von der Länge des Programms abschrecken. Auf dem ersten Blick sieht es komplizierter aus als es ist. Sie können das Programm ja Ihren Bedürfnissen anpassen. Wie z.B. "Mülldateien" (*.tmp,*.bak....) aufsuchen und löschen mit remove oder unlink. Oder gar ganze Verzeichnisse löschen mit rmdir (Vorausgesetzt sie haben den Inhalt des Verzeichnisses schon entleert). Oder sie können mittels chmod die Zugriffsrechte auf einzelne oder mehreren Dateien verändern. Es gibt noch viel mehr Beispiele. Versucht einfach an dem Programm herumzubasteln und neue Funktionen einzufügen. Wenn Ihr wollt könnt Ihr das ganze dann mal an mir schicken und ich werde es hier veröffentlichen.

Nun wollen wir als Beispiel ein Programm mit opendir,readdir und anderen Funktionen erstellen. In meinem Home-Verzeichnis sieht es nach einer Woche fürchterlich aus. *.c-Dateien, *.txt;*.log;*.png;*.pl...Dateien füllen das ganze Home-Verzeichnis. Ich habe mir dafür ein Programm geschrieben, mit dem ich Dateien nach Endung in ein Verzeichnis, das ich ebenfalls erstelle, mit Änderung der Zugriffrechte kopieren kann. Da mehrere Leute auf meinem PC zugreifen können und ich nicht will das mir diese Dateien aus versehen gelöscht werden. Ich räume mit diesem Programm einmal im Monat mein Home Verzeichnis auf mit folgendem Aufruf....

backup -dw c,txt,png,pl, /home/pronix/backup_december01

Damit werden alle Dateien vom Working Directory mit den Endungen *.c;*.txt;*.png;*.pl in ein neues Verzeichnis backup_december01 kopiert. Zur Sicherheit setze ich mit der Option 'w' einen Schreibschutz.

Weiter Mögliche Eingaben wären....

backup -b c,txt,png neuesVerzeichnis

Alle *c,*txt und *png - Dateien als Backup (-b=backup) in neuesVerzeichnis kopieren.

backup -d  jpg,bmp,gif neuesVerzeichnis

Alle *jpg,*.bmp und *.gif - Dateien in neuesVerzeichnis kopieren und im aktuellen Verzeichnis löschen.

backup -dw bak,log neuesVerzeichnis

Alle *.bak und *log Dateien ins neue Verzeichnis kopieren und das Schreibrecht auf diese Datei löschen (w=writable). Die Dateien im aktuellen Verzeichnis werden gelöscht. 'r' für Leserecht und Schreibrecht löschen. Auführecht nie setzen.

Folgende Funktionen werden benötigt....

  1. Schalter auswerten (Handlung und Zugriffrecht)
  2. Datei-endungen auswerten und in Liste speichern
  3. Eine Liste der Dateien mit diesen Endungen erstellen (readdir)
  4. Neue Verzeichnis erstellen (mkdir)
  5. Liste der Dateien durchlaufen und ins neue Verzeichnis kopieren (fread,fwrite) mit entsprechenden Zugriffrechten.
  6. Dateien eventuell löschen
  7. Neues Verzeichnis lesen (opendir, readdir)
Um es gleich Vorwegzunehemen. Das Programm ist auf meinen Bedürfnissen angepasst. Sie können sich viele weiter Funktionen einbauen bzw. die vorhandenen auf Ihre Bedürfnisse anpassen. Das Programm ist zwar etas Umfangreicher, aber mit dem bisher gelernten dürfte es für sie kein Problem darstellen es zu verstehen.

Hier nun der Quellcode.......

/*Download:bakup.c*/
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <dirent.h> #include <sys/types.h> #include <fcntl.h> #define BUF 4096 #define MSG "\nVerwendung : backup -[OPTION] [DATEIENDUNG] [NEUESVERZEICHNIS]\n"\ "\nOptionen -b = Alle Dateien mit [DATEIENDUNG] als Backup\n"\ " in [NEUESVERZEICHNIS] kopieren\n"\ " -d = Alle Dateien mit [DATEIENDUNG] als Backup\n"\ " in [NEUESVERZEICHNIS] kopieren und diese\n"\ " Dateien im aktuellen Verzeichnis löschen\n"\ " -dw= Wie -d nur ohne Schreibrechte auf alle Dateien\n"\ " -dr= Wie -d nur ohne Schreib.-und-Leserechte auf Dateien\n"\ " -bw= Wie -d nur ohne Schreibrechte auf alle Dateien\n"\ " im neuen Verzeichnis.\n"\ " -br= Wie -d nur ohne Schreib.-und-Leserechte auf Dateien\n"\ " im neuen Verzeichnis.\n\n"\ "[DATEIENDUNG] Schreibweise : txt,c,o,jpg, (mit Komma trennen und beenden)\n\n" /*Flags für die Optionen von -1 bis 5 */ enum{NO_OPTION=-1,BACKUP,DELETE,DELETE_0444,DELETE_0000,BACKUP_0444,BACKUP_0000}; static int option; char *dateiendung[10]; /*Auf 10 Dateiarten minimiert*/ char working_D[255]; /*Working Directory*/ char new_Directory[255]; /*Verzeichnis wo das Backup abgelegt wird*/ /*Funktionsprototypen*/ void error_exit(char *,...); int get_option(char *); void read_Directory(char *); void copy_from_to(char *); /*Fehlerausgabe mit exit*/ void error_exit(char *s,...) { fprintf(stderr, "%s\n",s); exit(0); } /*2.Argument Optionen auswerten*/ int get_option(char *opt) { if(strcmp(opt,"-b") == 0) return BACKUP; else if(strcmp(opt,"-d")==0) return DELETE; else if(strcmp(opt,"-dw") == 0) return DELETE_0444; else if(strcmp(opt,"-dr") == 0) return DELETE_0000; else if(strcmp(opt,"-bw") == 0) return BACKUP_0444; else if(strcmp(opt,"-br") == 0) return BACKUP_0000; else return NO_OPTION; } /*Verzeichnis lesen*/ void read_Directory(char *d) { DIR *dir; struct dirent *dirzeiger; char *p,*p2; int i,j; char backup[255]; if( (dir=opendir(d)) == NULL) error_exit("Konnte Verzeichnis %s nicht öffnen\n",d); while( (dirzeiger=readdir(dir)) != NULL) { i=0;j=0; while(dateiendung[i] != NULL) { /*Wir brauchen nur die Dateien mit den richtigen Endungen*/ /*Zeiger auf Punkt, falls vorhanden*/ if( (p=strchr((*dirzeiger).d_name,'.')) != NULL) /*Eine Position weiter und mit Liste dateiendung überprüfen*/ if(strcmp((++p),dateiendung[i]) == 0){ p2=(*dirzeiger).d_name; strncpy(backup,p2,strlen(p2)+1); /*Als Kontrolle*/ /*printf("%s\n",backup);*/ copy_from_to(backup); j++; break; } i++; } } closedir(dir); } void copy_from_to(char *b) { int r,w; char dir1[255], dir2[255]; int i,n; char puffer[BUF]; int permission; strcpy(dir1,working_D); strcat(dir1,"/"); strcat(dir1,b); strcpy(dir2, new_Directory); strcat(dir2,"/"); strcat(dir2,b); printf("from : %s to : %s\n",dir1,dir2); /*Datei zum lesen öffnen*/ r=open(dir1,O_RDONLY); /*Datei zum Schreiben im neuen Verzeichnis öffnen*/ w=open(dir2,O_WRONLY|O_CREAT|O_TRUNC); if(r==-1) fprintf(stderr,"Konnte Datei %s nicht öffnen(read)\n",dir1); if(w==-1) fprintf(stderr,"Konnte Datei %s nicht öffnen(write)\n",dir2); /*Kopieren ins neue Verzeichnis*/ while( (n=read(r, &puffer, BUF)) > 0) write(w,&puffer,n); /*War ein Flag zum löschen gesetzt?*/ if(option==DELETE || option==DELETE_0444 || option==DELETE_0000) if(remove(dir1) == -1) /*dann weg damit*/ fprintf(stderr, "Konnte %s nicht löschen!\n",dir1); /*Haben wir als Option ein r oder w für Zugriffrechte verwendet?*/ if(option==BACKUP_0000 || option==DELETE_0000) permission=0000; else if(option==BACKUP_0444 || option==DELETE_0444) permission=0444; else permission=0750; if(fchmod(w,permission) == -1) fprintf(stderr,"Konnte Zugriffrechte für %s nicht ändern\n",dir2); close(r);close(w); } int main(int argc, char **argv) { int i; char *p; char arg2[255]; if(argc < 4) error_exit(MSG); /*Optionen auswerten*/ option=get_option(argv[1]); if(option == NO_OPTION) error_exit(MSG); /*Dateiendungen auswerten*/ strncpy(arg2, argv[2], strlen(argv[2])); p=strtok(arg2,","); for(i=0; i<10 && p!=NULL; i++) { if ((*(dateiendung+i)=malloc(strlen(p))) == NULL) error_exit("Konnte keinen Speicher reservieren"); strncpy(*(dateiendung+i),p, strlen(p)); p=strtok(NULL,","); } printf("Nach folgenden Dateien wird nun gesucht : "); for(i=0; *(dateiendung+i) != NULL; i++) printf("*.%s ; ",*(dateiendung+i)); printf("\n"); /*Ende Dateiendungen auswerten*/ /*aktuelles Verzeichnis Öffnen und Lesen */ if((getcwd(working_D, sizeof(working_D))) == NULL) error_exit("Konnte Working Directory nicht ermitteln"); else printf("Im folgenden Verzeichnis wird gesucht : %s\n",working_D); strncpy(new_Directory, argv[3], strlen(argv[3])); printf("Backup kommt in folgendes Verzeichnis : %s\n",new_Directory); /*Verzeichnis für Backup anlegen*/ if(mkdir(new_Directory,0755) == -1) error_exit("Konnte neuen Verzeichnis nicht erstellen"); read_Directory(working_D); /*Verzeichnis lesen und Liste erstellen*/ return 0; }

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf