Advanced Java Services | Lesen und Schreiben von Textdateien |
Wir verwenden die Klasse FileReader. Will man einen gepufferten Zugriff, so verwendet man stattdessen die Klasse BufferedReader, die ihrerseits auf die Klasse Reader aufsetzt. FileReader und BufferedReader sind reale Ableitungen der abstrakten Basisklasse Reader (siehe Hierarchie der Readerklassen ).
Wir verwenden die Klasse FileReader. Will man einen gepufferten Zugriff, so verwendet man stattdessen die Klasse BufferedReader, die ihrerseits auf die Klasse Reader aufsetzt. FileReader und BufferedReader sind reale Ableitungen der abstrakten Basisklasse Reader (siehe Hierarchie der Readerklassen ).
Wichtige Konstruktorender Klasse FileReader | |
---|---|
FileReader(String fileName) |
Creates a new FileReader, given the File to read from. |
FileReader(File file) |
Creates a new FileReader, given the File to read from. |
Wichtige Konstruktoren der Klasse BufferedReader | |
---|---|
BufferedReader(Reader in) |
Create a buffering character-input stream that uses a default-sized input buffer. Man muß schon den Quellcode lesen, um herauszufinden, wie groß "default-sized" ist. Dort finden man den folgenden Eintrag: private static int defaultCharBufferSize = 8192; |
BufferedReader(Reader in, int sz) |
Create a buffering character-input stream that uses an input buffer of the specified size. |
Reader stellt drei Lesemethoden zum Einlesen von Textdaten aus Dateien bereit.
Lesemethoden der Klasse Reader | |
---|---|
Returntyp | Name der Methode |
int |
read() Read a single character. Returns the character read, as an integer in the range 0 to 65535 (0x00-0xffff), or -1 if the end of the stream has been reached. |
int |
read(char[] cbuf) Read characters into an array. Returns the number of characters read, or -1 if the end of the stream has been reached. |
abstract int |
read(char[] cbuf, int off, int len) Read characters into a portion of an array. Returns the number of characters read, or -1 if the end of the stream has been reached. Parameters: cbuf - Destination buffer, off - Offset at which to start storing characters, len - Maximum number of characters to read. |
Die ersten beiden read-Methoden stützen sich dabei auf die dritte abstrakte Methode, wie ein Blick
in den Quellcode zeigt.
Quellcode der ersten read-Methode:
public int read() throws IOException { char cb[] = new char[1]; if (read(cb, 0, 1) == -1) return -1; else return cb[0]; }
Quellcode der zweiten read-Methode:
public int read(char cbuf[]) throws IOException { return read(cbuf, 0, cbuf.length); }
Damit ist auch klar, wie die zweite Methode arbeitet, sie liest höchstens so viele Zeichen ein, wie in dem Array Platz haben. Die folgenden Beispiele demonstrieren die drei Methoden.
FileReader fr = null; try { String fileName="TextDateiLesen.java"; fr = new FileReader(fileName); StringBuffer sb = new StringBuffer(); int ch; while( (ch=fr.read()) != -1 ) sb.append((char)ch); System.out.println(sb.toString()); } /*catch(FileNotFoundException ex) { System.out.println(ex); }*/ catch(IOException ex) { System.out.println(ex); } finally { try { if(fr!=null) fr.close(); } catch(Exception ex) { } }
FileReader fr = null; try { String text ; String fileName="TextDateiLesen2.java"; File file = new File(fileName) ; int len = (int)file.length() ; char[] buf = new char[len] ; fr = new FileReader(file); fr.read(buf) ; text = new String(buf); System.out.println(text); } /*catch(FileNotFoundException ex) { System.out.println(ex); }*/ catch(IOException ex) { System.out.println(ex); } finally { try { if(fr!=null) fr.close(); } catch(Exception ex) { } }
FileReader fr = null; try { String text ; String fileName="TextDateiLesen2.java"; File file = new File(fileName) ; int len = (int)file.length() ; char[] buf = new char[len] ; fr = new FileReader(file); fr.read(buf, 0, len) ; text = new String(buf); System.out.println(text); } /*catch(FileNotFoundException ex) { System.out.println(ex); }*/ catch(IOException ex) { System.out.println(ex); } finally { try { if(fr!=null) fr.close(); } catch(Exception ex) { } }
Die Klasse BufferedReader stellt eine weitere Einlesemethode zur Verfügung, die ein zeilenweises Einlesen einer Textdatei ermöglicht.
Zusätzliche Lesemethode der Klasse BufferedReader | |
---|---|
Returntyp | Name der Methode |
String |
readLine() Read a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed. Returns a String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached. |
FileReader fr = null; BufferedReader br = null; try { String fileName="TextDateiLesen3.java"; File file = new File(fileName) ; fr = new FileReader(file); br = new BufferedReader(fr) ; String line ; StringBuffer sb = new StringBuffer(); // systemeigenes Zeilenumbruchszeichen ermitteln String sep = System.getProperty("line.separator"); while( (line=br.readLine()) != null ) sb.append(line+sep) ; System.out.println(sb); //ganze Datei ausgegeben } /*catch(FileNotFoundException ex) { System.out.println(ex); }*/ catch(IOException ex) { System.out.println(ex); } finally { try { if(br!=null) br.close(); if(fr!=null) fr.close(); } catch(Exception ex) { } }
readLine() verhält sich neutral und liest keinen Zeilenumbruch mit ein. So kann man selbst bestimmen, welches Zeilenumbruchszeichen man verwendet. Im obigen Fall wird das systemeigene Zeilenumbruchszeichen verwendet, welches man sich über die SystemProperties besorgt.
Seit der Zeit der Telegraphie, in der der ASCII-Code eingeführt wurde, werden die Zeichen
CR = carriage return = ASCII-Code 13 = '\r'
und
LF = line feed = ASCII-Code 10 = '\n'
zur Zeilentrennung verwendet. Als der ASCII-Code zur Speicherung von Texten in Dateien
übernommen wurde, konnte man sich nicht auf ein einheitliches Zeilenumbruchszeichen verständigen.
So gibt es nun drei verschiedene Zeilenumbruchszeichen:
Max-Systeme verwenden CR = carriage return = ASCII-Code 13 = '\r'
Unix-Systeme verwenden LF = line feed = ASCII-Code 10 = '\n'
Windows-Systeme verwenden CR+LF = carriage return+line feed = "\r\n"
Beim Einlesen mit den read()-Methoden werden sämtliche Zeichen gelesen, also auch die
Zeilenumbruchszeichen. Nicht alle Varianten können können von den graphischen Komponenten in Java
umgesetzt werden.
java.awt.TextArea | |
---|---|
Methode | Verhalten |
setText() | Mac-Zeilenumbrüche werden als schwarze Recktecke dargestellt. Es wird kein Zeilenumbruch gemacht. Unix-Zeilenumbrüche und Windows-Zeilenumbrüche werden korrekt dargestellt. |
getText() | In die TextArea eingegebene Zeilenumbrüche werden als Unix-Zeilenumbrüche in den Text aufgenommen. Es kann also im Text einer TextArea u.U. verschiedene Zeilenumbruchstile geben. |
javax.swing.JTextArea | |
---|---|
Methode | Verhalten |
setText() | Mac-Zeilenumbrüche werden nicht dargestellt. Es wird kein Zeilenumbruch gemacht.
Der Text läuft nathlos weiter. Unix-Zeilenumbrüche und Windows-Zeilenumbrüche werden korrekt dargestellt. |
getText() | In die JTextArea eingegebene Zeilenumbrüche werden als Unix-Zeilenumbrüche in den Text aufgenommen. Es kann also im Text einer JTextArea u.U. verschiedene Zeilenumbruchstile geben. |
Die Klasse System liefert das (systemabhängige) Zeilenumbruchszeichen über die Properties der Klasse System.
String separator = System.getProperty("line.separator") ;
Die Klasse Character besitzt eine Konstante
Character.LINE_SEPARATOR
Diese Konstante steht für CR, also für das Zeilenumbruchszeichen auf Mac.
Mit einem StringReader kann man Strings so behandeln wie Dateien. Steckt man ihn in einen BufferedReader, so steht die readLine()-Methode zur Verfügung und man kann den String zeilenumbruchsneutral einlesen. Das folgende Beispiel liest einen String mit unterschiedlichen Zeilenumbruchszeichen und gibt einen neuen String mit Unix-Zeilenumbruchszeichen zurück:
public String insertUnixLineWrappings(String text) { BufferedReader br = null; try { //"Datei öffnen" br = new BufferedReader( new StringReader(text) ); StringBuffer sb = new StringBuffer(); String line; // "Datei" lesen while ( (line=br.readLine() )!=null ) sb.append(line + '\n'); return sb.toString(); } catch(IOException ex) { return null; } finally { try { if(br!=null) br.close(); } catch(Exception ex) { } } }
Natürlich kann man die Methode noch flexibler gestalten, indem man als zweiten Parameter das einzufügende Zeilenumbruchszeichen eingibt:
public String insertLineWrappings(String text, String style) { if ( style.equals("\r") || style.equals("\n") || style.equals("\r\n") { BufferedReader br = null; try { //"Datei öffnen" BufferedReader br = new BufferedReader( new StringReader(text) ); StringBuffer sb = new StringBuffer(); String line; // "Datei" lesen while ( (line=br.readLine() )!=null ) sb.append(line + style); // Datei schließen br.close(); return sb.toString(); } catch(IOException ex) { return null; } finally { try { if(br!=null) br.close(); } catch(Exception ex) { } } } else throw new IllegalArgumentException("second paramater contains no wrap style"); }
Die beiden letzten Beispiele werfen die Frage auf, in welcher Reihenfolge try, catch und finally abgearbeitet werden, wenn in den Blöcken return auftritt. Die Antwort: Der finally-Block wird in jedem Fall ausgeführt und er wird zudem vor return abgearbeitet!
Zum Schreiben von Dateien braucht man die Klasse FileWriter. Will man einen gepufferten Zugriff, so verwendet man zusätzlich die Klasse BufferedWriter. Beide Klassen sind reale Ableitungen der abstrakten Basisklasse Writer, die das Gegenstück zur Klasse Reader ist (siehe Hierarchie der Writerklassen ).
Wichtige Konstruktorender Klasse FileWriter | |
---|---|
FileWriter(String fileName) |
Constructs a FileWriter object given a file name. |
FileWriter(String fileName, boolean append) |
Constructs a FileWriter object given a file name with a boolean indicating whether or not to append the data written. |
FileWriter(File file) |
Constructs a FileWriter object given a file object. |
FileWriter(File file, boolean append) | Constructs a FileWriter object given a file object with a boolean indicating whether or not to append the data written. |
Die Konstruktoren der Klasse BufferedWriter | |
---|---|
BufferedWriter(Writer out) |
Create a buffering character-output stream that uses a default-sized input buffer. Man muß schon den Quellcode lesen, um herauszufinden, wie groß "default-sized" ist. Dort finden man den folgenden Eintrag: private static int defaultCharBufferSize = 8192; |
BufferedWriter(Writer out, int sz) |
Create a buffering character-output stream that uses an input buffer of the specified size. |
Writer stellt gleich fünf Methoden zum Schreiben von Textdaten in Dateien bereit.
Schreibmethoden der Klasse Writer | |
---|---|
Returntyp | Name der Methode |
void | write(char[] cbuf)
Write an array of characters. |
abstract void | write(char[] cbuf, int off, int len) Write a portion of an array of characters. Parameters: cbuf - Array of characters, off - Offset from which to start writing characters, len - Number of characters to write. |
void | write(int c) Write a single character. The character to be written is contained in the 16 low-order bits of the given integer value; the 16 high-order bits are ignored. |
void | write(String str) Write a string |
void | write(String str, int off, int len) Write a portion of a string. Parameters: str - a String, off - offset from which to start writing characters, len - number of characters to write |
Weitere wichtige Methoden der Klasse Writer | |
---|---|
Returntyp | Name der Methode |
Writer | append(char c) Appends the specified character to this writer (Since 1.5). |
Writer | append(CharSequence csq) Appends the specified character sequence to this writer (Since 1.5). |
abstract void | flush() Flush the stream. |
Die realen write-Methoden stützen sich letzten Endes alle auf die abstrakte write-Methode. Hier nur der Quellcode von zwei der vier Methoden.
public void write(char cbuf[]) throws IOException { write(cbuf, 0, cbuf.length); // abstrakt }
public void write(String str) throws IOException { write(str, 0, str.length()); // diese Methode verwendet dann die abstrakte write-Methode. }
FileWriter fw = null; try { fw = new FileWriter("datei.name"); fw.write(text); // text ist ein String } catch(IOException ex) { System.out.println(ex); } finally { if (fw != null) try { fw.close(); } catch(Exception ex) { } }
Zum Schreiben eines betriebssystemabhängigen Zeilenumbruchs bietet BufferedWriter die Methode newLine() an.
Nützliche Methode der Klasse BufferedWriter | |
---|---|
Returntyp | Name der Methode |
void | newLine()
Write a line separator. The line separator string is defined by the system property line.separator, and is not necessarily a single newline ('\n') character: String separator = System.getProperty("line.separator"). |
BufferedWriter bw = null; try { bw = new BufferedWriter( new FileWriter("datei.name") ); bw.write(text); // text ist ein String // bw.newLine() ; // evtl. Zeilenumbruchszeichen einfügen } catch(IOException ex) { System.out.println(ex); } finally { if (bw != null) try { bw.close(); } catch(Exception ex) { } }