66. Systemprogrammierung I: Verzeichnisse

Viele Dinge, die man eigentlich häufig braucht – z.B. Verzeichnisse auslesen, Prozesse erzeugen, Netzwerkverbindungen öffnen –, sind leider (wenigstens in C) nicht wirklich standardisiert. Auch wenn das nicht portabel zu machen ist, sind doch die Metaphern oft ähnlich. Deshalb diskutiere ich hier einige Techniken im Linux/glibc-Umfeld, die Übertragung auf andere Plattformen bleibt euch überlassen.

In Python sind die meisten dieser Funktioen im Modul os enthalten. Dort sorgt die Bibliothek für eine Umsetzung auf die für die jeweilige Plattform angemessenen Aufrufe, so dass viele der Aufgaben hier in Python portabel ausgeführt werden können.

Verzeichnisse

Kennt man den Namen einer Datei und will sie einfach löschen, gibt es dafür die Funktion remove(char *pathname) aus stdio.h.

Die Funktion remove ist portabel, d.h. in ANSI C definiert. Unter Unix hieß sie konventionell unlink (und ist so immer noch in unistd.h deklariert, tut aber exakt das Gleiche wie remove), weil die Datei nicht zwingend gleich gelöscht wird. Wie bei den Dateisystemen diskutiert, ist es bei Unix-Dateisystemen durchaus möglich, eine Datei zu löschen (d.h. ihren Verzeichniseintrag zu entfernen), ohne dass der zugehörige inode (oder was immer) freigegeben wird – etwa im Falle von hard links.

Warnung: soft links sind quasi nur Dateien, in denen der Name der Zieldatei drinsteht. Wenn auf eine Datei, die ihr löscht, ein soft link existiert, kümmert das Unix nicht, es löscht die Datei, und der soft link zeigt ins Leere.

Das “Auslesen” eines Directories geht ziemlich analog zu FILEs: Es gibt (aus dirent.h und ggf. sys/types.h)

  • einen Typ DIR
  • DIR *opendir(char *dirname)
  • int closedir(DIR *dir)
  • struct dirent *readdir(DIR *dir)

Es gibt dabei natürlich keine Mode-Flags in opendir (auf ein Verzeichnis schreiben ist reichlich sinnlos), und die Eingabe gibt keine chars oder char* zurück, sondern einen Pointer auf einen (statisch in DIR liegenden) struct. Diesen sollte man zwischen zwei Aufrufen von readdir ausgewertet haben, weil die Daten überschrieben werden, ganz wie in unserer Implementation von getNextWord.

In dem struct ist das Feld char *d_name definiert, der Name des Verzeichniseintrags, der gerade betrachtet wird. Die Reihenfolge, in der die Namen kommen, ist nicht definiert.

Ein einfaches Programm, das einen Verzeichnisinhalt ausgibt:

#include <stdio.h>
#include <dirent.h>

int main(int argc, char **argv)
{
  DIR *dir;
  struct dirent *entry;

  if (argc==2 && (dir=opendir(argv[1]))) {
    while ((entry=readdir(dir))) {
      puts(entry->d_name);
    }
    closedir(dir);
  } else {
    fprintf(stderr, "You messed it up.\n");
  }
  return 0;
}

Anlegen bzw. Löschen von Verzeichnissen mit mkdir(char *path) bzw. rmdir(char *path).

Dateien und Verzeichnisse lassen sich mit

rename(char *oldname, char *newname)

umbenennen. Dabei darf sich auch das Verzeichnis ändern, solange Quell- und Zielname auf demselben Filesystem liegen.


Markus Demleitner

Copyright Notice