Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.
 
Inhaltsverzeichnis
Vorwort
1 Neues in Java 8 und Java 7
2 Fortgeschrittene String-Verarbeitung
3 Threads und nebenläufige Programmierung
4 Datenstrukturen und Algorithmen
5 Raum und Zeit
6 Dateien, Verzeichnisse und Dateizugriffe
7 Datenströme
8 Die eXtensible Markup Language (XML)
9 Dateiformate
10 Grafische Oberflächen mit Swing
11 Grafikprogrammierung
12 JavaFX
13 Netzwerkprogrammierung
14 Verteilte Programmierung mit RMI
15 RESTful und SOAP-Web-Services
16 Technologien für die Infrastruktur
17 Typen, Reflection und Annotationen
18 Dynamische Übersetzung und Skriptsprachen
19 Logging und Monitoring
20 Sicherheitskonzepte
21 Datenbankmanagement mit JDBC
22 Java Native Interface (JNI)
23 Dienstprogramme für die Java-Umgebung
Stichwortverzeichnis

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java SE 8 Standard-Bibliothek von Christian Ullenboom
Das Handbuch für Java-Entwickler
Buch: Java SE 8 Standard-Bibliothek

Java SE 8 Standard-Bibliothek
Pfeil 6 Dateien, Verzeichnisse und Dateizugriffe
Pfeil 6.1 Alte und neue Welt in java.io und java.nio
Pfeil 6.1.1 java.io-Paket mit File-Klasse
Pfeil 6.1.2 NIO.2 und java.nio-Paket
Pfeil 6.2 Dateisysteme und Pfade
Pfeil 6.2.1 FileSystem und Path
Pfeil 6.2.2 Die Utility-Klasse Files
Pfeil 6.2.3 Dateien kopieren und verschieben
Pfeil 6.2.4 Dateiattribute *
Pfeil 6.2.5 Neue Dateien, Verzeichnisse, symbolische Verknüpfungen anlegen und löschen
Pfeil 6.2.6 MIME-Typen herausfinden *
Pfeil 6.2.7 Verzeichnislistings (DirectoryStream/Stream) und Filter *
Pfeil 6.2.8 Rekursives Ablaufen des Verzeichnisbaums *
Pfeil 6.2.9 Rekursiv nach Dateien/Ordnern suchen mit Files.find(…) *
Pfeil 6.2.10 Dateisysteme und Dateisystemattribute *
Pfeil 6.2.11 Verzeichnisse im Dateisystem überwachen *
Pfeil 6.3 Datei- und Verzeichnis-Operationen mit der Klasse File
Pfeil 6.3.1 Dateien und Verzeichnisse mit der Klasse File
Pfeil 6.3.2 Verzeichnis oder Datei? Existiert es?
Pfeil 6.3.3 Verzeichnis- und Dateieigenschaften/-attribute
Pfeil 6.3.4 Umbenennen und Verzeichnisse anlegen
Pfeil 6.3.5 Verzeichnisse auflisten und Dateien filtern
Pfeil 6.3.6 Dateien berühren, neue Dateien anlegen, temporäre Dateien
Pfeil 6.3.7 Dateien und Verzeichnisse löschen
Pfeil 6.3.8 Wurzelverzeichnis, Laufwerksnamen, Plattenspeicher *
Pfeil 6.3.9 URL-, URI- und Path-Objekte aus einem File-Objekt ableiten *
Pfeil 6.3.10 Mit Locking Dateien sperren *
Pfeil 6.3.11 Sicherheitsprüfung *
Pfeil 6.3.12 Zugriff auf SMB-Server mit jCIFS *
Pfeil 6.4 Dateien mit wahlfreiem Zugriff
Pfeil 6.4.1 Ein RandomAccessFile zum Lesen und Schreiben öffnen
Pfeil 6.4.2 Aus dem RandomAccessFile lesen
Pfeil 6.4.3 Schreiben mit RandomAccessFile
Pfeil 6.4.4 Die Länge des RandomAccessFile
Pfeil 6.4.5 Hin und her in der Datei
Pfeil 6.5 Wahlfreier Zugriff mit SeekableByteChannel und ByteBuffer *
Pfeil 6.5.1 SeekableByteChannel
Pfeil 6.5.2 ByteBuffer
Pfeil 6.5.3 Beispiel mit Path + SeekableByteChannel + ByteBuffer
Pfeil 6.5.4 FileChannel
Pfeil 6.6 Zum Weiterlesen
 
Zum Seitenanfang

6.3Datei- und Verzeichnis-Operationen mit der Klasse File Zur vorigen ÜberschriftZur nächsten Überschrift

Die Klasse File hat die Aufgabe, Dateioperationen plattformunabhängig durchzuführen. Plattformunabhängigkeit ist aber auch eine Einschränkung, denn wie sollen Rechte vergeben werden, wenn dies etwa der Macintosh mit Mac OS X oder ein Android-Smartphone nicht unterstützen? Unix und Windows haben zwei völlig verschiedene Ansätze zur Rechteverwaltung. Die File-Klasse ignoriert diese Frage und bietet überhaupt keine Lösung. In NIO.2 jedoch geht Java einen anderen Weg und neigt wieder deutlich mehr zu plattformspezifischen Details.

Das alte File und der neue Path

Die Klasse File ist schon immer da gewesen und stark mit dem lokalen Dateisystem verbunden. So findet sich der Typ File weiterhin bei vielen Operationen. Wenn Runtime.exec(String[] cmdarray, String[] envp, File dir) einen Hintergrundprozess startet, dann ist dir genau das Startverzeichnis. Eine Abstraktion auf virtuelle Dateisysteme ist unpassend, und File passt als Typ sehr gut. Doch obwohl sich Pfade vom NIO.2-Typ Path schon an einigen Stellen in der Java-API finden lassen, sind doch immer noch viele APIs mit File ausgestattet. Dass ImageIO.read (File input) nur ein File-Objekt annimmt, aber kein Path-Objekt, um ein Bild zu laden, ist schade, wo es doch auch eine read(InputStream) und read(URL)-Methode gibt. Die Bibliotheksdesigner haben bisher keine Notwendigkeit gesehen, das nachzubessern, vielleicht aus deswegen nicht, weil Entwickler die Möglichkeit haben, etwa mit Files.newInputStream(path) von einem Pfad einen Eingabestrom zu erfragen. Der Weg ist auch der beste, denn vom Path ein File-Objekt zu erfragen und dann Methoden aufzurufen, die das File-Objekt annehmen, birgt eine Gefahr: Von einem NIO.2-Dateisystem, etwa ZIP, ein File-Objekt zu erfragen, wird nicht funktionieren, weil es die Datei vom File-Objekt ja gar nicht im lokalen Verzeichnis gibt! Einige Klasse erwarten nur File-Objekte und nichts anderes, also auch keinen Strom, und hier zeigt sich, dass diese Klassen nicht auf virtuellen Dateisystemen funktionieren können. Etwa der JFileChooser, der operiert nur auf dem lokalen Dateisystem, was sich an JFileChooser.getSelectedFile() und JFileChooser.setCurrentDirectory(File dir) ablesen lässt.

 
Zum Seitenanfang

6.3.1Dateien und Verzeichnisse mit der Klasse File Zur vorigen ÜberschriftZur nächsten Überschrift

Ein File-Objekt repräsentiert einen Datei- oder Verzeichnisnamen im Dateisystem. Die Datei oder das Verzeichnis, das das File-Objekt beschreibt, muss nicht physikalisch existieren. Der Verweis wird durch einen Pfadnamen spezifiziert. Dieser kann absolut oder relativ zum aktuellen Verzeichnis angegeben werden.

[zB]Beispiel

Erzeuge ein File-Objekt für das Laufwerk C:

File f = new File( "C:/" );
System.out.println( f ); // C:\

Folgende Konstruktoren erzeugen ein File-Objekt:

class java.io.File
implements Serializable, Comparable<File>
  • File(String pathname)
    Erzeugt ein File-Objekt aus einem Dateinamen.

  • File( String parent, String child)

  • File(File parent, String child)
    Setzt ein neues File-Objekt aus einem Basisverzeichnis und einem weiteren Teil zusammen, der auch wieder ein Verzeichnis oder ein Dateiname sein kann.

  • File(URI uri)
    Erfragt von uri den Pfadnamen (uri.getPath()) und erzeugt ein neues File-Objekt. Ist uri gleich null, folgt eine NullPointerException. Ist der URI falsch formuliert, gibt es eine IllegalArgumentException.

Die Pfadangabe kann in allen Fällen absolut sein, muss es aber nicht.

Pfadtrenner

Die Angabe des Pfades ist wegen der Pfadtrenner plattformabhängig. Auf Windows-Rechnern trennt ein Backslash »\« die Pfade, auf Unix-Maschinen ein normaler Slash »/« und unter dem älteren MAC OS 9 ein Doppelpunkt.

Glücklicherweise speichert die Klasse File den Pfadtrenner in zwei öffentlichen Konstanten: File.separatorChar[ 74 ](Eigentlich sollte der Variablenname großgeschrieben werden, da die Variable als public static final char eine Konstante ist.) ist ein char, und File.separator stellt den Pfadtrenner als String bereit (dies ist wiederum auf System.getProperty("file.separator") zurückzuführen).

[»]Hinweis

Wie bei den Dateitrennern gibt es einen Unterschied bei der Darstellung des Wurzelverzeichnisses. Unter Unix ist dies ein einzelnes Divis »/«, und unter Windows steht die Laufwerksbezeichnung vor dem Doppelpunkt und dem Backslash-Zeichen (»Z:\«).

Klassendiagramm für File

Abbildung 6.9Klassendiagramm für File

Namen erfragen und auflösen

Mit einem File-Objekt erfragen ganz unterschiedliche Methoden den Dateinamen, den kompletten Pfad, das vorangehende Verzeichnis und ob eine Angabe absolut oder relativ ist. Bei einigen Methoden lässt sich wählen, ob die Rückgabe ein String-Objekt mit dem Dateinamen sein soll oder ein File-Objekt.

[zB]Beispiel

Liefere einen Dateinamen, bei dem die relativen Bezüge aufgelöst sind:

try {
File f = new File("C:/./WasNDas//..\\Programme/").getCanonicalFile();
System.out.println( f ); // C:\Programme
}
catch ( IOException e ) { e.printStackTrace(); }

Nicht viele Methoden der File-Klasse lösen eine IOException aus, diese ist eher eine Ausnahme.

class java.io.File
implements Serializable, Comparable<File>
  • String getName()
    Gibt den Dateinamen zurück.

  • String getPath()
    Gibt den Pfadnamen zurück.

  • String getAbsolutePath()

  • File getAbsoluteFile()
    Liefert den absoluten Pfad. Ist das Objekt kein absoluter Pfadname, so wird ein Objekt aus dem aktuellen Verzeichnis, einem Separator-Zeichen und dem Dateinamen aufgebaut.

  • String getCanonicalPath () throws IOException

  • File getCanonicalFile() throws IOException
    Gibt den Pfadnamen des Dateiobjekts zurück, der keine relativen Pfadangaben mehr enthält. Kann im Gegensatz zu den anderen Pfadmethoden eine IOException aufrufen, da mitunter verbotene Dateizugriffe erfolgen.

  • String getParent()

  • File getParentFile()
    Gibt den Pfad des Vorgängers als String- oder File-Objekt zurück. Die Rückgabe ist null, wenn es keinen Vater gibt, etwa beim Wurzelverzeichnis.

  • boolean isAbsolute()
    Liefert true, wenn der Pfad in der systemabhängigen Notation absolut ist.

 
Zum Seitenanfang

6.3.2Verzeichnis oder Datei? Existiert es? Zur vorigen ÜberschriftZur nächsten Überschrift

Das File-Objekt muss nicht unbedingt eine existierende Datei oder ein existierendes Verzeichnis repräsentieren. Für Dateioperationen mit File-Objekten und nachfolgendem Zugriff testet exists(), ob die Datei oder das Verzeichnis tatsächlich vorhanden ist. Da nun aber ein File-Objekt Dateien sowie Verzeichnisse gleichzeitig repräsentiert, ermöglichen isDirectory() und isFile() eine genauere Aussage über den File-Typ. Es kann gut sein, dass für ein File weder isDirectory() noch isFile() die Rückgabe true liefern (in Java können nur normale Dateien erzeugt werden).

class java.io.File
implements Serializable, Comparable<File>
  • boolean exists()
    Liefert true, wenn das File-Objekt eine existierende Datei oder einen existierenden Ordner repräsentiert.

  • boolean isDirectory()
    Gibt true zurück, wenn es sich um ein Verzeichnis handelt.

  • boolean isFile()
    Liefert true, wenn es sich um eine »normale« Datei handelt (kein Verzeichnis und keine Datei, die vom zugrunde liegenden Betriebssystem als besonders markiert wird, keine Blockdateien, Verknüpfungen).

 
Zum Seitenanfang

6.3.3Verzeichnis- und Dateieigenschaften/-attribute Zur vorigen ÜberschriftZur nächsten Überschrift

Eine Datei oder ein Verzeichnis besitzt zahlreiche Eigenschaften, die sich mit Anfragemethoden auslesen lassen. In einigen wenigen Fällen lassen sich die Attribute auch ändern.

class java.io.File
implements Serializable, Comparable<File>
  • boolean canExecute(), boolean canRead(), boolean canWrite()
    Liefert true, wenn die Ausführungsrechte/Leserechte/Schreibrechte gesetzt sind.

  • long length()
    Gibt die Länge der Datei in Byte zurück oder 0L, wenn die Datei nicht existiert oder es sich um ein Verzeichnis handelt.

Änderungsdatum einer Datei

Eine Datei verfügt unter jedem Dateisystem nicht nur über Attribute wie Größe und Rechte, sondern verwaltet auch das Datum der letzten Änderung. Letzteres nennt sich Zeitstempel. Die File-Klasse verfügt zum Abfragen dieser Zeit über die Methode lastModified() und zum Setzen über setLastModified().

Die Methode setLastModified(long) ändert (wenn möglich) den Zeitstempel, und ein anschließender Aufruf von lastModified() liefert die gesetzte Zeit (womöglich gerundet) zurück. Die Methode ist von vielfachem Nutzen, aber in Hinblick auf die Sicherheit bedenklich, denn ein Programm kann den Dateiinhalt einschließlich des Zeitstempels ändern. Auf den ersten Blick ist nicht mehr erkennbar, dass eine Veränderung der Datei vorgenommen wurde. Doch die Methode ist von größerem Nutzen bei der Programmerstellung, wo Quellcodedateien etwa mit Objektdateien verbunden sind. Nur über einen Zeitstempel ist eine einigermaßen intelligente Projektdateiverwaltung möglich.

Dabei bleibt es verwunderlich, warum lastModified() nicht als veraltet ausgezeichnet ist und zu getLastModified() wurde, wo doch nun die passende Methode zum Setzen der Namensgebung genügt.

class java.io.File
implements Serializable, Comparable<File>
  • long lastModified()
    Liefert den Zeitpunkt, an dem die Datei zum letzten Mal geändert wurde. Die Zeit wird in Millisekunden ab dem 1. Januar 1970, 00:00:00 UTC, gemessen. Die Methode liefert 0, wenn die Datei nicht existiert oder ein Ein-/Ausgabefehler auftritt.

  • boolean setLastModified(long time)
    Setzt die Zeit (wann die Datei zuletzt geändert wurde). Die Zeit ist wiederum in Millisekunden seit dem 1. Januar 1970 angegeben. Ist das Argument negativ, dann wird eine IllegalArgumentException ausgelöst.

[»]Hinweis

Zwar lässt Java die Ermittlung der Zeit der letzten Änderung zu, doch gilt dies nicht für die Erzeugungszeit. Das Standard-Dateisystem von Unix-Systemen speichert diese Zeit nicht. Windows speichert sie hingegen schon, sodass hier grundsätzlich der Zugriff, etwa über JNI, möglich wäre. Legt ein Java-Programm die Dateien an, deren Anlegezeiten später wichtig sind, müssen die Zeiten beim Anlegen gemessen und gespeichert werden. Falls die Datei nicht verändert wird, stimmt lastModified() mit der Anlegezeit überein.

Dateiattribute verändern

Zu den Anfragemethoden canXXX() kann ein File-Objekt auch Dateiattribute verändern.

[zB]Beispiel

Lege eine neue temporäre Datei an, und teste das Lesen und Verändern des Lese-Schreib-Attributs. Nach dem Test lösche die Datei wieder:

Listing 6.22com/tutego/insel/io/file/PermissionDemo.java, main()

File f = File.createTempFile( "bla", "blub" );
System.out.printf( "readable=%s, writable=%s%n", f.canRead(), f.canWrite() );
f.setReadOnly();
System.out.printf( "readable=%s, writable=%s%n", f.canRead(), f.canWrite() );
f.setWritable( true );
System.out.printf( "readable=%s, writable=%s%n", f.canRead(), f.canWrite() );
f.deleteOnExit();

Die Ausgabe ist:

readable=true, writable=true
readable=true, writable=false
readable=true, writable=true

Es gibt Methoden wie setLastModified(long), die auf dem Dateiobjekt wirklich eine Änderung ausführen. Insofern muss die Aussage in der API-Dokumentation genau genommen werden: »Instances of the File class are immutable; that is, once created, the abstract pathname represented by a File object will never change.« Nur der Dateiname ist immutable, aber nicht die Zustände.

class java.io.File
implements Serializable, Comparable<File>
  • boolean setReadOnly()
    Setzt die Datei auf Nur-Lesezugriff. Liefert »wahr«, wenn die Änderung möglich war.

  • boolean setExecutable(boolean executable, boolean ownerOnly)

  • boolean setReadable(boolean readable, boolean ownerOnly)

  • boolean setWritable(boolean writable, boolean ownerOnly)
    Setzt das Recht zum Ausführen/Lesen/Schreiben der Datei. Ist ownerOnly true, gilt das Recht nur für den Benutzer, sonst für alle.

  • boolean setExecutable(boolean executable)

  • boolean setReadable(boolean readable)

  • boolean setWritable(boolean writable)
    Die Implementierung leitet weiter an die mit zwei Parametern deklarierte Methode setXXXable(boolean, boolean), und das zweite Argument ist true.

Die setXXX(…)-Methoden melden über die Rückgabe, ob die Veränderung möglich war.

Ist eine Datei eine Verknüpfung? *

Wer nicht mindestens Java 7 nutzen kann, der muss die Frage nach der Dateiverknüpfung über eine interne Klasse sun.awt.shell.ShellFolder beantworten lassen. Die Klasse liefert bei .lnk‐Dateien unter Windows mit isLink() ein klares true/false, gibt die Zieladresse mit getLinkLocation() und auf Anfrage mit getIcon() das assoziierte Datei-Icon als Image dazu an:

Listing 6.23ShellFolderDemo.java, main()

String s = "C:\\Dokumente und Einstellungen\\All Users\\Startmenü\\"+
"Programmzugriff und -standards.lnk";
ShellFolder folder = ShellFolder.getShellFolder( new File( s ) );
System.out.println( folder.getFolderType() ); // Verknüpfung
if ( folder.isLink() )
System.out.println( folder.getLinkLocation() ); // C:\WINDOWS\system32\control.exe
 
Zum Seitenanfang

6.3.4Umbenennen und Verzeichnisse anlegen Zur vorigen ÜberschriftZur nächsten Überschrift

Mit mkdir() lassen sich Verzeichnisse anlegen und mit renameTo(File) Dateien oder Verzeichnisse umbenennen.

class java.io.File
implements Serializable, Comparable<File>
  • boolean mkdir()
    Legt das Unterverzeichnis an.

  • boolean mkdirs()
    Legt das Unterverzeichnis inklusive weiterer Verzeichnisse an.

  • boolean renameTo(File d)
    Benennt die Datei in den Namen um, der durch das File-Objekt d gegeben ist. Ging alles gut, wird true zurückgegeben. Bei zwei Dateinamen alt und neu benennt new File(alt).renameTo(new File(neu)); die Datei um. Die Methode muss vom Betriebssystem nicht atomar ausgeführt werden, und die tatsächliche Implementierung ist von der JVM und vom Betriebssystem abhängig.

Über renameTo(File) sollte noch ein Wort verloren werden: File-Objekte sind immutable, stehen also immer nur für genau eine Datei. Ändert sich der Dateiname, ist das File-Objekt ungültig, und es ist kein Zugriff mehr über dieses File-Objekt erlaubt. Auch wenn eine Laufzeitumgebung keine Exception auslöst, sind alle folgenden Ergebnisse von Anfragen unsinnig.

 
Zum Seitenanfang

6.3.5Verzeichnisse auflisten und Dateien filtern Zur vorigen ÜberschriftZur nächsten Überschrift

Um eine Verzeichnisanzeige oder einen Dateiauswahldialog zu programmieren, benötigen wir eine Liste von Dateien, die in einem Verzeichnis liegen. Ein Verzeichnis kann reine Dateien oder auch wieder Unterverzeichnisse besitzen. Die list(…)- und listFiles(…)-Methoden der Klasse File geben ein Feld von Zeichenketten mit Dateien und Verzeichnissen bzw. ein Feld von File-Objekten mit den enthaltenen Elementen zurück.

class java.io.File
implements Serializable, Comparable<File>
  • File[] listFiles()

  • String[] list()
    Gibt eine Liste der Dateien in einem Verzeichnis als File-Array oder String-Array zurück. Das Feld enthält weder ».« noch »..«.

[zB]Beispiel

Ein einfacher Directory-Befehl ist leicht mittels einiger Zeilen programmiert:

String[] entries = new File( "." ).list();
System.out.println( Arrays.toString(entries) );

Die einfache Methode list() liefert dabei nur relative Pfade, also einfach den Dateinamen oder den Verzeichnisnamen. Den absoluten Namen zu einer Dateiquelle müssen wir also erst zusammensetzen. Praktischer ist da schon die Methode listFiles(), da wir hier komplette File-Objekte bekommen, die ihre ganze Pfadangabe schon kennen. Wir können den Pfad mit getName() erfragen.

Dateien mit FilenameFilter und FileFilter nach Kriterien filtern

Ein Filter filtert aus den Dateinamen diejenigen heraus, die einem gesetzten Kriterium genügen. Eine Möglichkeit ist, nach den Endungen zu separieren. Doch auch komplexere Selektionen sind denkbar; so kann in die Datei hineingesehen werden, ob sie beispielsweise bestimmte Informationen am Dateianfang enthält. Besonders für Macintosh-Benutzer ist dies wichtig zu wissen, denn dort sind die Dateien nicht nach Endungen sortiert. Die Information über den Dateityp liegt in der Datei selbst kodiert. Unter Windows und Unix-Systemen ist das anders, da ist die Dateiendung alles und identifiziert den Dateityp. Fehlt er, stehen Windows und Unix-Systeme orientierungslos da und wissen mit der Datei nichts anzufangen; sie können dann weder das richtige Programm zur Anzeige noch und zum Bearbeiten auswählen.

Sollen aus einer Liste von Dateien einige mit besonderen Eigenschaften herausgenommen werden, so müssen wir dies nicht selbst programmieren. Der Schlüssel hierzu sind die Schnittstellen FilenameFilter und FileFilter. Wenn wir etwas später den grafischen Dateiauswahldialog kennenlernen, so können wir dort auch den FilenameFilter einsetzen.[ 75 ](Leider hatte der Fehlerteufel seine Finger im Spiel, und der FilenameFilter funktioniert nicht, weil der FileSelector fehlerhaft ist. Obwohl die Funktionalität dokumentiert ist, findet sich unter der Bug-Nummer 4031440 kurz: »The main issue is that support for FilenameFilter in the FileDialog class was never implemented on any platform – it’s not that there’s a bug which needs to be fixed, but that there’s no code to run nor was the design ever evaluated to see if it *could* be implemented on our target platforms.«) Eine Filterklasse implementiert die Operation accept(File) so, dass alle von accept(File) angenommenen Dateien den Rückgabewert true liefern.

interface java.io.FileFilter
  • boolean accept(File pathname)
    Muss true liefern, wenn die Datei pathname in die Ergebnisliste aufgenommen werden soll.

interface java.io.FilenameFilter
  • boolean accept(File dir, String name)
    Muss true liefern, wenn die Datei mit dem Namen name im Verzeichnis dir in die Ergebnisliste soll.

Beim FilenameFilter empfängt accept(File, String) zwei Argumente, nämlich das Verzeichnis dir, in dem die Datei name liegt, und beim FileFilter enthält pathname die voll qualifizierte Datei schon direkt als File-Objekt. (Was für Dateien in einem Verzeichnis gilt, gilt ebenso für Unterverzeichnisse.) Im Fall von FileFilter liefert also pathname.getName() den Dateinamen.

Klassendiagramm der beiden Filter-Schnittstellen

Abbildung 6.10Klassendiagramm der beiden Filter-Schnittstellen

[zB]Beispiel

Wollen wir nur auf Textdateien reagieren, so geben wir ein true bei allen Dateien mit der Endung.txt zurück. Die anderen werden mit false abgelehnt.

Listing 6.24com/tutego/insel/io/file/TxtFilenameFilter.java, TxtFilenameFilter

public class TxtFilenameFilter implements FilenameFilter {
@Override public boolean accept( File f, String s ) {
return new File(f, s).isFile() &&
s.toLowerCase().endsWith( ".txt" );
}
}

Exemplare der implementierenden Klassen werden der Methode list(…) bzw. listFiles(…) als Argument übergeben.

class java.io.File
implements Serializable, Comparable<File>
  • String[] list(FilenameFilter filter)
    Wie list(), nur filtert ein spezielles FilenameFilter-Objekt Objekte heraus.

  • File[] listFiles(FilenameFilter filter)
    Wie listFiles(), nur filtert ein spezielles FilenameFilter-Objekt Objekte heraus.

  • File[] listFiles(FileFilter filter)
    Wie list(), nur filtert ein spezielles FileFilter-Objekt bestimmte Objekte heraus.

Nun können list(…) mit dem FilenameFilter und listFiles(…) mit dem FileFilter bzw. FilenameFilter aufgerufen werden. Die Methode erfragt zuerst alle Dateien und Unterverzeichnisse und ruft dann für jeden Eintrag die accept(…)-Methode auf. Bei der Rückgabe true nimmt die Auflistungsmethode den Eintrag in eine interne Liste auf, die dann später als Feld zurückgegeben wird.

[zB]Beispiel

Zur Implementierung von FilenameFilter und FileFilter bieten sich innere Klassen an. In einem Beispiel soll listFiles(…) nur Unterverzeichnisse von dir zurückliefern:

Listing 6.25com/tutego/insel/io/file/SubDir.java, main() Ausschnitt

File[] subDirs = dir.listFiles( new FileFilter() {
@Override public boolean accept( File d ) {
return d.isDirectory();
} } );

Dateien aus dem aktuellen Verzeichnis filtern

Wir können somit ein einfaches Verzeichnisprogramm programmieren, indem wir die Möglichkeiten von getProperty(…) und listFiles(…) zu einem Beispiel zusammenfügen. Zusätzlich wollen wir nur Dateien mit der Endung .txt angezeigt bekommen:

Listing 6.26com/tutego/insel/io/file/Dir.java, main()

File userdir = new File( System.getProperty("user.dir") );
System.out.println( userdir );

for ( File file : userdir.listFiles( new TxtFilenameFilter() ) )
System.out.println( file );

[»]Hinweis

Die zusätzliche Java-Bibliothek Commons IO (http://commons.apache.org/proper/commons-io/) bietet über das Paket org.apache.commons.io.filefilter vielfältige Datei-Filter, wie SuffixFileFilter oder WildcardFilter. Auch NIO.2 hat hier etwas mehr zu bieten, zum Beispiel die Globbing-Syntax, mit der sich »*.txt« scheiben lässt.

 
Zum Seitenanfang

6.3.6Dateien berühren, neue Dateien anlegen, temporäre Dateien Zur vorigen ÜberschriftZur nächsten Überschrift

Unter dem Unix-System gibt es das Shell-Kommando touch, das wir in einer einfachen Variante in Java umsetzen wollen. Das Programm berührt (engl. touch) eine Datei, indem der Zeitstempel auf das aktuelle Datum gesetzt wird. Wie beim Kommando touch soll unser Java-Programm über alle auf der Kommandozeile übergebenen Dateien gehen und sie berühren. Falls eine Datei nicht existiert, soll sie kurzerhand angelegt werden:

Listing 6.27com/tutego/insel/io/file/Touch.java

package com.tutego.insel.io.file;

import java.io.*;

public class Touch {
public static void main( String[] args ) {
for ( String s : args ) {
File f = new File( s );

if ( f.exists() ) {
if ( f.setLastModified( System.currentTimeMillis() ) )
System.out.println( "Berührte " + s );
else
System.out.println( "Konnte nicht berühren " + s );
}
else {
try {
f.createNewFile();
System.out.println( "Legte neue Datei an " + s );
} catch ( IOException e ) { e.printStackTrace(); }
}
}
}
}

Gibt setLastModified(long) den Wahrheitswert false zurück, so wissen wir, dass die Operation fehlschlug, und geben eine Informationsmeldung aus.

class java.io.File
implements Serializable, Comparable<File>
  • boolean createNewFile() throws IOException
    Legt atomar eine neue, leere Datei mit dem im File-Objekt gespeicherten Namen an, wenn eine Datei mit diesem Namen noch nicht existiert.

  • static File createTempFile(String prefix, String suffix) throws IOException
    Legt eine neue Datei im temporären Verzeichnis an. Das Verzeichnis findet sich häufig unter einem Standard-Unix /tmp oder unter Windows C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp. Der Dateiname setzt sich aus einem benutzerdefinierten Präfix, einer Zufallsfolge und einem Suffix zusammen.

  • static File createTempFile(String prefix, String suffix, File directory)
    throws IOException
    Legt eine neue Datei im gewünschten Verzeichnis an. Der Dateiname setzt sich aus einem benutzerdefinierten Präfix, einer Zufallsfolge und einem Suffix zusammen.

 
Zum Seitenanfang

6.3.7Dateien und Verzeichnisse löschen Zur vorigen ÜberschriftZur nächsten Überschrift

Mithilfe der Methode delete() auf einem File-Objekt lässt sich eine Datei oder ein Verzeichnis entfernen. Diese Methode löscht wirklich! Sie ist nicht so zu verstehen, dass sie true liefert, falls die Datei potenziell gelöscht werden kann. Konnte die Laufzeitumgebung delete() nicht ausführen, so sollte die Rückgabe false sein. Ein zu löschendes Verzeichnis muss leer sein, andernfalls kann das Verzeichnis nicht gelöscht werden. Unsere unten stehende Implementierung geht dieses Problem so an, dass sie rekursiv die Unterverzeichnisse löscht.

class java.io.File
implements Serializable, Comparable<File>
  • boolean delete()
    Löscht die Datei oder das leere Verzeichnis. Falls die Datei nicht gelöscht werden konnte, gibt es keine Ausnahme, sondern den Rückgabewert false.

  • void deleteOnExit()
    Löscht die Datei bzw. das Verzeichnis, wenn die virtuelle Maschine korrekt beendet wird. Einmal vorgeschlagen, kann das Löschen nicht mehr rückgängig gemacht werden. Falls die JVM vorzeitig die Grätsche macht – Reinigungsfachkraft stolpert über Kabel –, kann natürlich die Datei möglicherweise noch immer nicht gelöscht sein, was insbesondere für temporäre Dateien, die über createTempFile(…) angelegt wurden, eventuell lästig wäre.

[»]Hinweis

Auf manchen Systemen liefert delete() die Rückgabe true, die Datei ist aber nicht gelöscht. Der Grund kann eine noch geöffnete Datei sein, mit der zum Beispiel ein Eingabestrom verbunden ist und die dadurch gelockt ist.

Rekursiv Verzeichnisse löschen

Die delete()-Methode operiert auf File-Objekten, die Dateien und auch Verzeichnisse repräsentieren. Doch wenn Verzeichnisse nicht leer sind, wird delete() nicht auch noch alle Dateien in diesem Verzeichnis inklusive aller Unterverzeichnisse löschen. Das muss von Hand erledigt werden, lässt sich aber in wenigen Programmcodezeilen rekursiv umsetzen. Eine eigene statische Methode deleteTree(File) soll einen Baum inklusive seiner Unterverzeichnisse löschen. listFiles() liefert ein Feld aller Elemente in dem Unterverzeichnis, und falls ein Element wiederum ein Verzeichnis ist, wird wieder deleteTree(File) auf diesem aufgerufen:

Listing 6.28com/tutego/insel/io/file/DeleteTree.java

package com.tutego.insel.io.file;

import java.io.File;

public class DeleteTree {
public static void deleteTree( File path ) {
for ( File file : path.listFiles() ) {
if ( file.isDirectory() )
deleteTree( file );
else
if ( ! file.delete() )
System.err.println( file + " konnte nicht gelöscht werden!" );
}

if ( ! path.delete() )
System.err.println( path + " konnte nicht gelöscht werden!" );
}

public static void main( String[] args ) {
deleteTree( new File("c:/ati/") );
}
}

[+]Tipp

Das Beispiel beachtet den Rückgabetyp von delete() und meldet einen Fehler, wenn das Verzeichnis oder die Datei nicht gelöscht werden konnte. Das sollte jedes Programm machen, da delete() keine Ausnahme auslöst, wenn es schiefging.

 
Zum Seitenanfang

6.3.8Wurzelverzeichnis, Laufwerksnamen, Plattenspeicher * Zur vorigen ÜberschriftZur nächsten Überschrift

Die statische Methode listRoots() gibt ein Feld von File-Objekten zurück. Jeder Eintrag des Feldes repräsentiert eine Wurzel (engl. root) des Dateisystems. Dies macht es einfach, Programme zu schreiben, die etwa über dem Dateisystem eine Suche ausführen. Da es unter Unix nur eine Wurzel gibt, ist der Rückgabewert von File.listRoots() immer »/« – ein anderes Root gibt es nicht. Unter Windows wird es aber zu einem richtigen Feld, da es mehrere Wurzeln für die Partitionen oder logischen Laufwerke gibt. Die Wurzeln tragen Namen wie »A:« oder »Z:«. Dynamisch eingebundene Laufwerke, die etwa unter Unix mit mount integriert werden, oder Wechselfestplatten werden mit berücksichtigt. Die Liste wird immer dann aufgebaut, wenn listRoots() aufgerufen wird. Komplizierter ist es, wenn entfernte Dateibäume mittels NFS oder SMB eingebunden sind, weil es dann nicht darauf ankommt, ob das zuständige Programm eine Verbindung noch aktiv hält oder nicht. Denn nach einer abgelaufenen Zeit ohne Zugriff wird das Verzeichnis wieder aus der Liste genommen. Dies ist aber wieder sehr plattformabhängig.

[zB]Beispiel

Gewünscht ist eine Liste der verfügbaren Wurzeln mit der Angabe, ob auf das Gerät eine Zugriffsmöglichkeit besteht. Ist unter Windows etwa ein Diskettenlaufwerk eingebunden, befindet sich aber keine Diskette im Schacht, dann ist das Gerät nicht bereit. Ein Diskettenlaufwerk taucht in der Liste auf, aber exists() liefert false.

Listing 6.29com/tutego/insel/io/file/ListRoot.java, main()

for ( File root : File.listRoots() )
System.out.println( root.getPath() + " ist " +
(root.exists() ? "" : "nicht ") + "bereit" );

Bei der Ausgabe mit println(…) entspricht root.getPath() einem root.toString(). Da aber nicht unbedingt klar ist, dass toString() auf getPath() verweist, schreiben wir getPath() direkt.

class java.io.File
implements Serializable, Comparable<File>
  • static File[] listRoots()
    Liefert die verfügbaren Wurzeln der Dateisysteme oder null, falls keine Wurzeln festgestellt werden können. Jedes File-Objekt beschreibt eine Dateiwurzel. Es ist gewährleistet, dass alle kanonischen Pfadnamen mit einer der Wurzeln beginnen. Wurzeln, für die der SecurityManager den Zugriff verweigert, werden nicht aufgeführt. Das Feld ist leer, aber nicht null, falls es keine Dateisystem-Wurzeln gibt.

Namen der Laufwerke

Die Namen der Laufwerksbuchstaben sind ein wenig versteckt, denn eine Methode zum Erfragen ist nicht bei der Klasse File zu finden. Zwar liefert listRoots() schon einen passenden Anfang, um unter Windows die Laufwerke preiszugeben, aber die Namen liefert erst getSystemDisplayName(File) des FileSystemView-Objekts. Die Klasse gehört zu Swing und dort zum Dateiauswahldialog.

[zB]Beispiel

Zeige alle Laufwerksbuchstaben:

Listing 6.30com/tutego/insel/io/file/SystemDisplayName.java. main()

FileSystemView view = FileSystemView.getFileSystemView();
for ( File f : File.listRoots() )
System.out.println( view.getSystemDisplayName(f) );

Die Ausgabe ist bei mir:

WINDOWS (C:)
Daten (D:)
Share (S:)
abstract class javax.swing.filechooser.FileSystemView
  • static FileSystemView getFileSystemView()
    Statische Fabrikmethode, die ein Exemplar von FileSystemView liefert.

  • boolean isDrive(File dir)

  • boolean isFloppyDrive(File dir)

  • boolean isComputerNode(File dir)
    Ist dir ein Laufwerk/Wechsellaufwerk/Netzwerkknoten?

FileSystemView hält noch andere gute Methoden bereit, wie getHomeDirectory() oder isTraversable(File).

Freier Plattenspeicher

Die Methoden getFreeSpace(), getUsableSpace() und getTotalSpace() ermitteln den freien Plattenspeichers:

Listing 6.31com/tutego/insel/io/file/DiscSpace.java. main()

System.out.println( "Laufwerk Total Frei Nutzbar" );
System.out.println( "--------------------------------------" );

for ( File dir : File.listRoots() )
System.out.printf( "%s %6d MB %6d MB %6d MB%n", dir,
dir.getTotalSpace() / (1024*1024),
dir.getFreeSpace() / (1024*1024),
dir.getUsableSpace() / (1024*1024) );

Die Ausgabe ist bei mir:

Drive Total Free Usable
-----------------------------------
C:\ 10001 MB 1467 MB 1467 MB
D:\ 66283 MB 63477 MB 63477 MB
S:\ 32145 MB 3194 MB 3194 MB
 
Zum Seitenanfang

6.3.9URL-, URI- und Path-Objekte aus einem File-Objekt ableiten * Zur vorigen ÜberschriftZur nächsten Überschrift

Da es bei URL-Objekten recht häufig vorkommt, dass eine Datei die Basis ist, wurde die Methode toURI() in die Klasse File aufgenommen, über die sich mit toURL() ein URL-Objekt aufbauen lässt (eine Methode toURL() gibt es auch, nur ist diese veraltet).

File f = new File( "C:/Dokumente und Einstellungen/" );
URL u = f.toURL(); // veraltet!
System.out.println( u ); // file:/C:/Dokumente und Einstellungen/
u = f.toURI().toURL();
System.out.println( u ); // file:/C:/Dokumente%20und%20Einstellungen/

Da File-Objekte ebenfalls einen Pfad repräsentieren, kann das File-Objekt mit toPath() diesen Pfad vom Typ Path liefern. Umgekehrt liefert auf einem Path-Objekt die Methode toFile() wiederum ein File-Objekt.

class java.io.File
implements Serializable, Comparable<File>
  • URI toURI()
    Liefert ein URI-Objekt vom File-Objekt, über das toURL() ein URL-Objekt generiert.

  • Path toPath()
    Liefert den Pfadanteil als Path-Objekt.

 
Zum Seitenanfang

6.3.10Mit Locking Dateien sperren * Zur vorigen ÜberschriftZur nächsten Überschrift

Damit eine Datei gegen konkurrierenden parallelen Zugriff geschützt ist, lässt sie sich über Locking absichern. Um einen Lock für Dateien zu erwerben, bietet die Java-API ein FileLock-Objekt. So ein FileLock bekommt ein Programm von der Methode lock() eines FileChannels – ein FileChannel wiederum kommt von getChannel(), einer Methode, die FileInputStream, FileOutputStream oder RandomAccessFile anbieten.

[zB]Beispiel

Öffne eine Datei, erzeuge exklusiven Zugriff, und schreibe Daten:

FileOutputStream fos = new FileOutputStream( file );
try ( FileLock fileLock = fos.getChannel().tryLock() ) {
fos.write( … );
}

Hinweis: Die übliche Schreibweise OutputStream fos funktioniert natürlich nicht, da ein allgemeiner OutputStream keine getChannel()-Methode bietet.

Die lock(…)-Methode liefert als Ergebnis ein FileLock-Objekt. Das wiederum bietet einige Methoden, wobei für uns nur release() bzw. close() interessant sind, die den Lock wieder freigeben. FileLock implementiert die Schnittstelle AutoCloseable, sodass ein FileLock auch mit try mit Ressourcen verwendet werden kann, wie im Beispiel geschehen. Um zu testen, ob eine gegebene Datei gelockt ist, lässt sich tryLock() verwenden – etwa mit der folgenden statischen Hilfsmethode:

Listing 6.32com/tutego/insel/io/file/FileUtils.java, isLocked()

public static boolean isLocked( String filename ) {
try ( RandomAccessFile raf = new RandomAccessFile( filename, "rw" );
FileLock lock = raf.getChannel().tryLock() ) {
// Nothing to do here
}
catch ( IOException e ) {
return false;
}
return true;
}

Die Methoden tryLock(…) und lock(…) liefern ein FileLock-Objekt, und diese Ressource muss immer korrekt geschlossen werden.

[»]Hinweis

Unter Unix-Systemen gibt es kein eindeutig vorgeschriebenes Verfahren zum File-Locking,[ 76 ](Zum Beispiel mit dem Alleskönner fcntl() aus dem POSIX-Standard oder flock() von 4.2 BSD.) sodass Oracle das Sperren bisher nur so umsetzt, dass zwei Java-Programme sich gegenseitig nicht in die Quere kommen, es aber sein kann, dass ein anderes Unix-Programm diesen Lock nicht respektiert. So kann unter Unix eine Datei von mehreren Seiten gelesen werden, selbst wenn ein Java-Programm sie aktuell beschreibt. Auch kann eine Datei auf dem Dateisystem gelöscht werden, selbst wenn das Java-Programm sie noch offen hält. Das Windows-Betriebssystem unterstützt hingegen Locks. Wenn ein Prozess keinen Lock auf die Datei besitzt, kann der Prozess sie auch nicht lesen.

 
Zum Seitenanfang

6.3.11Sicherheitsprüfung * Zur vorigen ÜberschriftZur nächsten Überschrift

Wir müssen uns der Tatsache bewusst sein, dass verschiedene Methoden eine SecurityException auslösen können, sofern ein Security-Manager die Dateioperationen überwacht. Security-Manager kommen beispielsweise bei Applets zum Zuge. Folgende Methoden sind Kandidaten für eine SecurityException: exists(), canRead(), canWrite(), isDirectory(), lastModified(), length(), mkdir(), mkdirs(), list(), delete() und renameTo(File).

 
Zum Seitenanfang

6.3.12Zugriff auf SMB-Server mit jCIFS * Zur vorigen ÜberschriftZur nächsten Überschrift

Microsoft Windows nutzt zur Datei- und Verzeichnisfreigabe, zur Freigabe von Druckern und Kommunikationsschnittstellen das Protokoll SMB (Server Message Block). Es ist weit verbreitet, und jede aktuelle Windows-Version lässt sich als Client und Server konfigurieren – gleichzeitig gibt es unter Unix das populäre Samba, einen SMB-Server unter Open Source, der von Andrew Tridgell und Kollegen entwickelt wurde.

Mithilfe der jCIFS-SMB-Bibliothek (http://jcifs.samba.org/) kann ein Java-Programm auf Datei- und Verzeichnisfreigaben zugreifen und Freigaben auflisten. jCIFS ist eine erweiterte Implementierung von CIFS und unterstützt Unicode, Batching, verschlüsselte Authentifizierung, Transactions, das Remote Access Protocol (RAP) und Weiteres. Die Bibliothek steht unter der LGPL.

Die Klassen jcifs.smb.SmbFile, SmbFileInputStream und SmbFileOutputStream verhalten sich ähnlich wie java.io.File, FileInputStream und FileOutputStream. Sie werden mit einem Dateipfad (URL) parametrisiert, der mit smb:// beginnt. Um eine Datei zu beziehen, muss vorher der Server spezifiziert werden. Dazu dienen Eigenschaften wie WINS. Sie werden mit Config.setProperty("wins", "IP-Adresse"); gesetzt.

[zB]Beispiel

Lies eine Datei aus, und kopiere sie um:

InputStream in =
new SmbFileInputStream( "smb://user:passwd@host/c/My Documents/doc.txt" );
Path target = …
Files.copy( in, target );

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java SE 8 Standard-Bibliothek Java SE 8 Standard-Bibliothek
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Java ist auch eine Insel
Java ist auch eine Insel


Zum Rheinwerk-Shop: Professionell entwickeln mit Java EE 8
Professionell entwickeln mit Java EE 8


Zum Rheinwerk-Shop: Besser coden
Besser coden


Zum Rheinwerk-Shop: Entwurfsmuster
Entwurfsmuster


Zum Rheinwerk-Shop: IT-Projektmanagement
IT-Projektmanagement


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2018
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 
Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern