Tit   Inh   Ind   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   <<   <   >   >> 

13.5 Datei- und Verzeichnis-Handling



Im Paket java.io gibt es eine Klasse File, die als Abstraktion eines Dateinamens angesehen werden kann. File kann sowohl absolute als auch relative Namen unter UNIX und DOS/Windows (UNC und Laufwerksbuchstabe) repräsentieren und sowohl für eine Datei als auch für ein Verzeichnis stehen. Im Gegensatz zu den bisher besprochenen Klassen spielt der Inhalt einer Datei in der Klasse File keine Rolle. Statt dessen abstrahiert File den Namen und Zugriffspfad einer Datei und die Eigenschaften, die im Verzeichnis, in dem die Datei liegt, über sie gespeichert sind. Neben Dateien kann ein File-Objekt auch Verzeichnisse repräsentieren.

13.5.1 Konstruktion eines File-Objektes

Die Klasse File besitzt drei Konstruktoren:

public File(String pathname)

public File(String parent, String child)

public File(File parent, String child)
java.io.File

Wird lediglich der String pathname übergeben, so wird ein File-Objekt zu dem angegebenen Datei- oder Verzeichnisnamen konstruiert. Alternativ dazu kann der zweite Konstruktor verwendet werden, wenn Verzeichnis- und Dateiname getrennt übergeben werden sollen. Eine ähnliche Funktion übernimmt auch der dritte Konstruktor. Hier wird jedoch der übergebene Verzeichnisname als File-Objekt zur Verfügung gestellt.

Bei der Konstruktion von Datei- und Verzeichnisnamen unter MS-DOS ist zu beachten, daß der Separator (Backslash) gleichzeitig Escape-Zeichen für Strings ist und daher in Verzeichnis- oder Dateiliteralen doppelt angegeben werden muß (siehe Abschnitt 4.2.2).

 Warnung 

Beispiele für gültige Konstruktoraufrufe sind:

new File("TestFile.java");
new File("c:\\arc\\doku\\javacafe\\kap01.doc");
new File(".","TestFile.java");
new File("c:\\config.sys");

13.5.2 Zugriff auf Teile des Pfadnamens

Nachdem ein File-Objekt konstruiert ist, können die Methoden zum Zugriff auf die einzelnen Bestandteile des Dateinamens aufgerufen werden:

public String getName()

public String getPath()

public String getAbsolutePath()

public String getParent()
java.io.File

getName liefert den Namen der Datei oder des Verzeichnisses; eventuelle Verzeichnisinformationen sind nicht darin enthalten. getPath liefert den kompletten Namen inklusive darin enthaltener Verzeichnisinformationen.

Mit getAbsolutePath kann der absolute Pfadname für das File-Objekt ermittelt werden. Wurde das File-Objekt mit Hilfe eines absoluten Pfadnamens konstruiert, liefert getAbsolutePath genau diesen Namen. Wurde es dagegen mit einem relativen Namen konstruiert, so stellt getAbsolutePath den Namen des aktuellen Verzeichnisses vor den Namen. Dabei werden allerdings die Namen . und .. nicht interpretiert, so daß leicht Pfadangaben wie C:\ARC\DOKU\javacafe\examples\.\TestFile.java entstehen können, die in der Mitte einen oder mehrere Punkte enthalten.

Schließlich gibt es noch die Methode getParent, die den Namen des Vaterverzeichnisses ermittelt. Repräsentiert das File-Objekt eine Datei, ist das der Name des Verzeichnisses, in dem die Datei liegt. Handelt es sich um ein Verzeichnis, wird der Name des darüber liegenden Verzeichnisses geliefert. Gibt es kein Vaterverzeichnis, liefert getParent null zurück.

13.5.3 Informationen über die Datei

Die Klasse File besitzt eine ganze Reihe von Methoden, um Informationen über die durch das File-Objekt bezeichnete Datei oder das Verzeichnis zu gewinnen:

public boolean exists()

public boolean canWrite()

public boolean canRead()

public boolean isHidden()

public boolean isFile()

public boolean isDirectory()

public boolean isAbsolute()

public long lastModified()

public long length()
java.io.File

Mit exists kann getestet werden, ob die Datei oder das Verzeichnis überhaupt existiert. Die Methoden canWrite und canRead ermitteln, ob ein lesender bzw. schreibender Zugriff möglich ist, mit isHidden kann festgestellt werden, ob die Datei versteckt ist. Mit isFile und isDirectory kann unterschieden werden, ob es sich um eine Datei oder ein Verzeichnis handelt. isAbsolute gibt an, ob das Objekt mit Hilfe einer absoluten Pfadbezeichung konstruiert wurde.

lastModified liefert den Zeitpunkt der letzten Änderung der Datei in Millisekunden seit dem 1.1.1970. Dieser kann entweder direkt in Vergleichen verwendet werden, oder man benutzt ihn zur Konstruktion eines Date-Objekts. Das Date-Objekt kann beispielsweise an die Methode setTime der Klasse GregorianCalendar übergeben werden, um die einzelnen Uhrzeitkomponenten zu extrahieren.

13.5.4 Zugriff auf Verzeichnisse

Wurde ein File-Objekt für ein Verzeichnis konstruiert, so stehen weitere Methoden zur Verfügung, um auf die zusätzlichen Funktionen eines Verzeichnisses zuzugreifen. Mit Hilfe der Methode list ist es beispielsweise möglich, den Inhalt des Verzeichnisses auszulesen:

public String[] list()
java.io.File

list liefert ein Array von Strings, das für jeden gefundenen Verzeichniseintrag ein Element enthält. Die Liste enthält die Namen aller Dateien und Unterverzeichnisse mit Ausnahme von . und ... list gibt es noch in einer zweiten Variante, bei der die Auswahl der Verzeichniseinträge eingeschränkt werden kann. Dabei muß ein Objekt übergeben werden, das das Interface FilenameFilter implementiert. Dieses besitzt eine Methode accept, die für jede gefundene Datei aufgerufen wird und entscheidet, ob sie in die Liste aufgenommen werden soll oder nicht.

Zusätzlich gibt es die statische Methode listRoots, mit der eine Liste aller »Wurzeln« der verfügbaren Dateisysteme beschafft werden kann. Unter UNIX gibt es lediglich die Wurzel "/", während es unter Windows zu jedem Laufwerksbuchstaben eine Wurzel gibt.

Neben dem Zugriff auf die Verzeichniseinträge gibt es in der Klasse File auch Methoden, um Dateien oder Verzeichnisse zu löschen oder umzubenennen und um Verzeichnisse neu anzulegen:

public boolean mkdir()

public boolean mkdirs()

public boolean renameTo(File dest)

public boolean delete()
java.io.File

Die Methode delete löscht die durch das File-Objekt bezeichnete Datei. Mit renameTo wird das File-Objekt in das als Parameter übergebene Objekt umbenannt. Durch Aufruf von mkdir wird das spezifizierte Verzeichnis angelegt. Mit mkdirs werden sogar alle Vaterverzeichnisse automatisch angelegt, wenn sie noch nicht existieren. Alle Methoden geben true zurück, wenn sie ihre Aufgabe erfolgreich ausführen konnten; andernfalls geben sie false zurück.

Das folgende Listing zeigt die Verwendung der Klasse File und den Aufruf verschiedener Methoden:

001 /* TestFile.java */
002 
003 import java.io.*;
004 import java.util.*;
005 
006 public class TestFile
007 {
008    public static void main(String[] args)
009    {
010       File fil = new File("TestFile.java");
011       TestFile.printFileInfo(fil);
012       fil = new File("..");
013       TestFile.printFileInfo(fil);
014    }
015 
016    static void printFileInfo(File fil)
017    {
018       System.out.println("Name= "+fil.getName());
019       System.out.println("Path= "+fil.getPath());
020       System.out.println("AbsolutePath= "+fil.getAbsolutePath());
021       System.out.println("Parent= "+fil.getParent());
022       System.out.println("exists= "+fil.exists());
023       System.out.println("canWrite= "+fil.canWrite());
024       System.out.println("canRead= "+fil.canRead());
025       System.out.println("isFile= "+fil.isFile());
026       System.out.println("isDirectory= "+fil.isDirectory());
027       if (fil.isDirectory()) {
028          String fils[] = fil.list();
029          for (int i=0; i<fils.length; ++i) {
030             System.out.println("  "+fils[i]);
031          }
032       }
033       System.out.println("isAbsolute= "+fil.isAbsolute());
034       System.out.println(
035          "lastModified= "+(new Date(fil.lastModified()))
036       );
037       System.out.println("length= "+fil.length());
038       System.out.println("");
039    }
040 }
TestFile.java
Listing 13.11: Verwendung der Klasse File

 Beispiel 

Ein Aufruf des Programms liefert folgende Ausgabe:

Name= TestFile.java
Path= TestFile.java
AbsolutePath= C:\ARC\DOKU\java\examples\TestFile.java
Parent= null
exists= true
canWrite= true
canRead= true
isFile= true
isDirectory= false
isAbsolute= false
lastModified= Sun Jan 05 17:15:56  1997
length= 1242

Name= ..
Path= ..
AbsolutePath= C:\ARC\DOKU\java\examples\..
Parent= null
exists= true
canWrite= true
canRead= true
isFile= false
isDirectory= true
  makefile
  html.cfg
  ...
  jdbc.sgml
  tuning.sgml
  reflection.sgml
isAbsolute= false
lastModified= Wed Jul 22 16:55:32 GMT+02:00 1998
length= 0

13.5.5 Anlegen von Dateien

Das Anlegen von Dateien wurde ja bereits in früheren Abschnitten dieses Kapitels behandelt. Hier soll es noch einmal erwähnt werden, weil die Klasse File zusätzlich die Möglichkeit bietet, temporäre Dateien und Lockdateien anzulegen. Beide Varianten haben ihre Anwendungen, und wir wollen sie im folgenden kurz vorstellen.

Temporäre Dateien

Zum Anlegen von temporären Dateien stehen zwei Varianten der Methode createTempFile zur Verfügung:

public static File createTempFile(
  String prefix, String suffix, File dir
)
  throws IOException

public static File createTempFile(
  String prefix, String suffix
)
  throws IOException
java.io.File

In beiden Fällen ist es erforderlich, einen Präfix- und einen Suffix-String zu spezifizieren. Als Präfix sollte normalerweise ein kurzer String von drei oder vier Buchstaben verwendet werden, der den Typ der temporären Datei identifziert. Der Suffix wird als Dateierweiterung verwendet, er könnte beispielsweise ".tmp" oder ".$$$" sein. createTempFile füllt den Platz zwischen Präfix und Erweiterung mit einer Zeichenkette, so daß der resultierende Dateiname eindeutig ist. Wird kein weiterer Parameter angegeben, legt die Methode eine neue temporäre Datei in einem systemspezifischen Verzeichnis an (typischerweise "\tmp" oder "\temp"). Alternativ kann als drittes Argument ein File-Objekt übergeben werden, das ein alternatives Verzeichnis für die temporäre Datei angibt.

Das folgende Listing zeigt ein einfaches Beispiel für die Anwendung der Methode createTempFile:

001 /* Listing1312.java */
002 
003 import java.io.*;
004 
005 public class Listing1312
006 {
007   public static void main(String args[])
008   {
009     try {
010       File tmp = File.createTempFile("xyz", ".tmp", null);
011     } catch (IOException e) {
012       System.out.println(e.toString());
013     }
014   }
015 }
Listing1312.java
Listing 13.12: Anlegen einer temporären Datei

 Beispiel 

Auf dem Testrechner wurden bei zweimaligem Aufruf des Programms im Verzeichnis "c:\tmp" die beiden folgenden Dateien angelegt:

xyz11626.tmp
xyz39639.tmp

Lockdateien

Ein häufiger Kritikpunkt der JDKs vor der Version 1.2 war, daß Java keine portable Möglichkeit zum Sperren von Dateien vorsah. Damit war es nicht (oder nur mit zusätzlichem Aufwand) möglich, Programme zu schreiben, die in einer Mehrbenutzerumgebung von unterschiedlichen Arbeitsplätzen gleichzeitig kontrolliert auf dieselben Dateien zugreifen.

 JDK1.1/1.2 

Mit den Methoden createNewFile und deleteOnExit bietet das JDK 1.2 nun eine rudimentäre Möglichkeit, diese Fähigkeiten zu realisieren:

public boolean createNewFile()
  throws IOException

public void deleteOnExit()
java.io.File

createNewFile erzeugt eine neue Datei aus dem Dateinamen des zugehörigen File-Objekts. Die Datei wird aber nur dann erzeugt, wenn sie bisher noch nicht vorhanden war. War sie dagegen bereits vorhanden, schlägt der Aufruf fehl und liefert false als Rückgabewert. Bei Erfolg wird die Datei angelegt und true zurückgegeben. Das JDK garantiert, daß die beiden erforderlichen Teiloperationen Feststellen, ob die Datei bereits existiert und Anlegen einer neuen Datei atomar ablaufen, also nicht unterbrechbar sind. Durch Aufruf von deleteOnExit kann sichergestellt werden, daß die Datei beim Beenden der VM in jedem Fall gelöscht wird, selbst wenn das Ende durch eine Ausnahme ausgelöst wurde.

Beide Methoden können nun auf unterschiedliche Weise zur Realisierung eines Locking-Systems verwendet werden. So kann beispielsweise der Name der Datei als zu sperrende Ressource und die Datei selbst als eigentliche Sperre angesehen werden. Dann würde es für jede zu sperrende Ressource eine eigene Sperrdatei geben (was bei einer großen Anzahl von potentiellen Ressourcen sehr viele einzelne Dateien bedeuten würde). Oder es ist denkbar, daß alle Sperrinformationen in einer einzigen Datei gehalten werden und nur der Zugriff auf diese Datei mit Hilfe einer Sperrdatei gesichert wird. Diese würde dann mit createNewFile in der Art eines Semaphors angelegt werden, um die Sperrdatei zu betreten, und nach Ende der Bearbeitung wieder entfernt werden.


 Tit   Inh   Ind   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   <<   <   >   >> 
Go To Java 2, Addison Wesley, Version 1.0.2, © 1999 Guido Krüger, http://www.gkrueger.com