Informatik II Dateien Seite 1 Th Letschert, THM Dateien - Konzept Datei Externer Datenspeicher CPU: Programmausführung Hauptspeicher: Programmcode und -Daten, direkt zugreifbar von CPU Festplatte etc.: nur indirekt zugreifbar über Betriebssystem-Aufrufe Extern Intern CPU / Prozessor Programmausführung Hauptspeicher Festplatte Programm-Code und -Daten Betriebssystem Seite 2 Dateien - Konzept Datei – rein virtuelles Konstrukt auf verschiedenen Abstraktionsebenen Abstraktionsebenen Platte: Magnetisierte Spuren, in Zylinder organisiert Plattencontroller: nummerierte Datenblöcke (von jeweils z.B. 512 Byte) Betriebssystem: (BS-) Datei = (scheinbar) zusammenhängender beliebig und variabel großer Datenbereich, nach Konventionen des Betriebssystems nutzbar Programm: (Programm-) Datei = (scheinbar) zusammenhängender beliebig und variabel großer Datenbereich, nach Konventionen der Programmiersprache nutzbar Ababd ahuwe diuhw Programmdatei (Programminterne Repräsentation.) Systemaufruf Programm Programm-API Betriebssystem BS-Datei (BS-internere Rep.) Seite 3 Daten Dateien - Konzept Datei-Repräsentant in Java Ababd ahuwediuh bis Java 1.6: java.io.File ab Java 1.7: java.nio.file.Path Programm Programm-API Betriebssystem Ab Java 7 stehen beide Varianten zur Verfügung. Es sollte aber i.A. die neuere Variante java.nio.file.Path verwendet werden. Gelegentlich muss aber auch bei Java 7 auf die Klasse java.io.File zurück gegriffen werden. (z.B. bei Verwendung des FileChooser.) Seite 4 Dateien – Verwendung / lesen Datei-Inhalt zeilenweise – mit der Klasse Scanner – lesen import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; public class Read_V6 { public static void main(String[] args) throws FileNotFoundException { File f = new File("blubber.txt"); } } Scanner scan = new Scanner(f); while (scan.hasNextLine()) { System.out.println(scan.nextLine()); } import import import import Java alle Versionen java.io.IOException; java.nio.file.Path; java.nio.file.Paths; java.util.Scanner; public class Read_V7 { public static void main(String[] args) throws IOException { Path p = Paths.get("blubber.txt"); } Scanner scan = new Scanner(p); while (scan.hasNextLine()) { System.out.println(scan.nextLine()); } ab Java 1.7 } Seite 5 Dateien – Verwendung / lesen Datei-Inhalt zeilenweise einlesen import import import import import java.io.IOException; java.nio.charset.Charset; java.nio.file.Files; java.nio.file.Path; java.nio.file.Paths; public class Read_V7_a { public static void main(String[] args) throws IOException { Path path = Paths.get("test.txt"); int i = 0; for ( String line: Files.readAllLines( path, Charset.defaultCharset()) ) { System.out.println("Zeile "+ ++i + line); } } ab Java 1.7 System.out.println("Die Datei enthält " + i + " Zeilen"); java.nio.file.Files } ist eine Helferklasse mit allerlei Nützlichem in Bezug auf Datei-Verarbeitung. java.nio.file.Paths ist eine Helferklasse mit Nützlichem in Bezug auf Datei-Operationen. Seite 6 Dateien – Verwendung / lesen Datei-Inhalt komplett als String einlesen import import import import import java.io.IOException; java.nio.charset.Charset; java.nio.file.Files; java.nio.file.Path; java.nio.file.Paths; public class Read_V7_b { public static void main(String[] args) throws IOException { Path path = Paths.get("blubber.txt"); String content = new String( Files.readAllBytes(path), Charset.defaultCharset()); ab Java 1.7 System.out.println(content); } } Verwendet aus der Klasse Files: byte[] readAllBytes(Path path) und den Konstruktor der Klasse String: String(byte[] bytes, Charset charset) Seite 7 Dateien – Verwendung / Auswahl Datei-Auswahl mit Auswahldialog – Java 6 Variante import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; import javax.swing.JFileChooser; public class Choose_V6 { public static void main(String[] args) throws FileNotFoundException { File f = null; JFileChooser fc = new JFileChooser(); int chooseResult = fc.showDialog(null, "Bitte Datei auswählen"); if (chooseResult == JFileChooser.APPROVE_OPTION) { f = fc.getSelectedFile(); } if (f != null) { Scanner scan = new Scanner(f); while (scan.hasNextLine()) { System.out.println(scan.nextLine()); } } } } Seite 8 Dateien – Verwendung / Auswahl Datei-Auswahl mit Auswahldialog – Java 7 Variante import import import import java.io.File; java.io.IOException; java.nio.file.Path; java.util.Scanner; import javax.swing.JFileChooser; public class Choose_V7 { public static void main(String[] args) throws IOException { } File f = null; JFileChooser fc = new JFileChooser(); int chooseResult = fc.showDialog(null, "Bitte Datei auswählen"); if (chooseResult == JFileChooser.APPROVE_OPTION) { f = fc.getSelectedFile(); } Wechsel zwischen den V-6 und V-7 if (f != null) { Repräsentanten: Path p = f.toPath(); Path path = file.toPath() Scanner scan = new Scanner(p); while (scan.hasNextLine()) { File file = path.toFile(); System.out.println(scan.nextLine()); } } } Seite 9 Dateien – Verwendung / schreiben Datei schreiben – Java 6 Variante import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; public class Write_V6 { public static void main(String[] args) throws IOException { String filePath = "balbla.txt"; PrintWriter pw = new PrintWriter( new FileWriter(filePath)); pw.println("Hallo"); pw.println("Welt!"); pw.close(); } Datei mit Printwriter verbinden Datei schließen nicht vergessen! } Seite 10 Dateien – Verwendung / schreiben Datei schreiben – Java 7 Variante import import import import import java.io.IOException; java.io.PrintWriter; java.nio.charset.Charset; java.nio.file.Files; java.nio.file.Paths; public class Write_V7 { public static void main(String[] args) throws IOException { String filePath = "balbla.txt"; PrintWriter pw = new PrintWriter( Files.newBufferedWriter( Paths.get(filePath), Charset.defaultCharset())); } pw.println("Hallo\n"); pw.println("Welt!\n"); pw.close(); Datei mit Printwriter verbinden Angabe in welchem Zeichensatz der Text codiert werden soll. Z.B: Zeichensatz des Systems oder UTF-8 - Charset.defaultCharset() - Charset.forName("UTF-8")) } Seite 11 Dateien – Verwendung / schreiben Datei schreiben – Java 7 Hallo Welt! balbla.txt import import import import import vorher java.io.IOException; java.nio.file.Files; java.nio.file.Path; java.nio.file.Paths; java.nio.file.StandardOpenOption; public class Write_V7a { public static void main(String[] args) throws IOException { Path path = Paths.get("balbla.txt"); String text = "Das ist ein zusätzlicher Text\nMit Zeilenvorschub!"; byte[] bytes = text.getBytes("UTF-8"); Files.write(path, bytes, StandardOpenOption.APPEND); } } Anhängendes Schreiben eines Strings auf eine Datei. Hallo Welt! Das ist ein zusätzlicher Text Mit Zeilenvorschub! java.nio.file.StandardOpenOption - APPEND - CREATE -… Siehe API-Dok. balbla.txt Seite 12 nachher Dateien – Verwendung / Dateioperationen Dateien erzeugen, kopieren, löschen – Java 7 import import import import import import java.io.IOException; java.nio.file.Files; java.nio.file.Path; java.nio.file.Paths; java.nio.file.StandardCopyOption; java.nio.file.StandardOpenOption; public class CreateCopyDelete { public static void main(String[] args) throws IOException { Path path_1 = Paths.get("D:\\Users\\Thomas\\datei_1.txt"); Path path_2 = Paths.get("D:\\Users\\Thomas\\datei_2.txt"); // 1. Datei erzeugen Files.createFile(path_1); // 1. Datei fuellen Files.write( path_1, "Ein wenig Text.\nAls Inhalt der Datei.\n".getBytes(), StandardOpenOption.WRITE); // 1. -> 2. Datei kopieren Files.copy(path_1, path_2, StandardCopyOption.REPLACE_EXISTING); } // 1. Datei loeschen Files.delete(path_1); } Seite 13 Dateien – Verwendung / anlysieren Datei analysieren – nur Java 7 import import import import java.io.File; java.io.IOException; java.nio.file.Files; java.nio.file.Path; import javax.swing.JFileChooser; public class AnalyseFile { public static void main(String[] args) throws IOException { File f = null; JFileChooser fc = new JFileChooser(); int chooseResult = fc.showDialog(null, "Bitte Datei auswählen"); if (chooseResult == JFileChooser.APPROVE_OPTION) { f = fc.getSelectedFile(); } if (f != null) { Path p = f.toPath(); if (Files.isRegularFile(p)) { System.out.println("Die Datei ist " + (Files.isExecutable(p) ? " ausfuehrbar" : " ") + (Files.isReadable(p) ? " lesbar" : " ") + (Files.isWritable(p) ? " schreibbar" : " ")); System.out.println("Der Dateityp ist: " + Files.probeContentType(p)); } } } } Seite 14 Texte analysieren Inhalt einer (Text-) Datei analysieren – alle Java-Versionen Datei-Inhalt = Text = String Standardverfahren der Textanalyse in Java: – StringTokenizer, StreamTokenizer veraltet – Scanner-Klasse Text strukturiert lesen (Wort für Wort, Zeile für Zeile, etc.) – String.split Methode Text an bestimmten Zeichen aufspalten – Klassen Pattern und Matcher für Fortgeschrittene Seite 15 Texte analysieren – Scanner Scanner-Klasse kann Texte (Strings) in beliebige Einheiten aufspalten und Einheit für Einheit zur Verfügung stellen verschiedene Arten von Text-Quellen sind dabei möglich. import java.util.Scanner; public class Scan { public static void main(String[] args) { String s = "Dies ist ein Text.\nEr besteht aus\nWorten und Zeilen.\n"; Scanner scanString = new Scanner(s); while (scanString.hasNext()) { System.out.println(scanString.next()); } System.out.println(); ScanString.close(); } } scanString = new Scanner(s); while (scanString.hasNextLine()) { System.out.println(scanString.nextLine()); } ScanString.close(); Wortweise aus einem String lesen Zeilenweise aus einem String lesen Dies ist ein Text. Er besteht aus Worten und Zeilen. Dies ist ein Text. Er besteht aus Worten und Zeilen. Scanner stellt diverse next...-Methoden zur Verfügung um den nächsten Text entsprechend einem bestimmten Typ zu analysieren. Siehe API-Doku. Seite 16 Texte analysieren – Scanner Scanner-Klasse kann Texte (Strings) in beliebige Einheiten aufspalten und Einheit für Einheit zur Verfügung stellen verschiedene Arten von Text-Quellen sind dabei möglich. import import import import java.io.IOException; java.nio.file.Path; java.nio.file.Paths; java.util.Scanner; public class Scan { public static void main(String[] args) throws IOException { Path path = Paths.get("/home/thomas/tmp/blubber1.txt"); Scanner scanFile = new Scanner(path); while (scanFile.hasNext()) { System.out.println(scanFile.next()); } System.out.println(); scanFile.close(); scanFile = new Scanner(p); while (scanFile.hasNextLine()) { System.out.println(scanFile.nextLine()); } } Wortweise aus einer Datei lesen Zeilenweise aus einer Datei lesen } Seite 17 Texte analysieren – String split Split-Methode der Klasse String kann Texte (Strings) in beliebige Einheiten aufspalten und Einheit für Einheit zur Verfügung stellen. Ähnlich zu Scanner es können allerdings nur Texte, die in Strings liegen, zerlegt werden und die Zerlegung erfolgt „in einem Schritt“. "Abc die Katze lief im Schnee." public class Split { public static void main(String[] args) throws IOException { String s = "Abc die Katze lief im Schnee."; String[] sParts = s.split("\\s"); } System.out.println(Arrays.asList(sParts)); ["Abc", "die", "Katze", "lief", "im", "Schnee."] } "\\s": Trenner: jede Folge von „weiße Zeichen“, Leerzeichen, Tabs, etc. (ein regulärer Ausdruck) Seite 18 Texte analysieren – Reguläre Ausdrücke Regulärer Ausdruck ➢ ➢ ➢ ➢ ➢ Ein Textmuster Vielfältige Verwendung bei der Textanalyse (unabhängig von Programmiersprachen) Wird als Konzept von allen (brauchbaren) anwendungsnahen Programmiersprachen angeboten Scanner und String.split verwenden reguläre Ausdrücke zur Definition der Trenner. Reguläre Basis-Ausdrücke in Java, Beispiele: x jedes Zeichen ist ein Muster das für sich selbst steht [xy] eine Klasse, ein x oder ein y regEx1 | regex2 ein Text der zu regEx1 oder regEx2 passt \\d eine Ziffer (= "[0123456789]" = "[0-9]" ) \\s ein weißes Zeichen \\w ein Wortzeichen (Buchstabe, Ziffer oder Unterstrich) . ein einziges beliebiges Zeichen regEx1* ein Text, der zu regEx1 passt, beliebig oft wiederholt \\. ein Punkt, Sonderzeichen wie Punkt brauchen „Escape“-Zeichen Seite 19 Texte analysieren – Reguläre Ausdrücke Regulärer Ausdruck Beispiel: public class Match { public static void main(String[] args) { String[] strings = { "Abc die Katze lief im Schnee.", "Peter schlief im Klee.", "Klausi trinkt gerne Tee mit Ruhm.", "Die Katze liebt keinen See."}; Katze String[] pattern = {"Katze", ".*ee.*"}; Etwas mit zwei e-s for (String s: strings) { System.out.println(s); for (String word : s.split("\\s")) { for (String pat: pattern) { if (word.matches(pat)) { System.out.println( "\tenthält das Wort " + word + " das zu " + pat + " passt"); } } Abc die Katze lief im Schnee. enthält das Wort Katze das zu Katze passt enthält das Wort Schnee. das zu .*ee.* passt Peter schlief im Klee. enthält das Wort Klee. das zu .*ee.* passt Klausi trinkt gerne Tee mit Ruhm. enthält das Wort Tee das zu .*ee.* passt Die Katze liebt keinen See. enthält das Wort Katze das zu Katze passt enthält das Wort See. das zu .*ee.* passt } } } Seite 20 Texte analysieren – Beispiel CVS-Datei CSV-Datei CSV: Comma Separated Values Standard-Format für Daten in Textform – ein (wichtiges) Format von sehr vielen Import- / Export-Format für Excel (und viele andere Programme) Tabellen ~ Textdateien – Zeilen der Tabelle : – Zellen der Tabelle : Zeilen der Textdatei durch Komma (Semikolon, Tab, …) getrennte Werte in einer Zeile Seite 21 Texte analysieren – Beispiel CVS-Datei CSV-Datei einlesen : Datei auswählen static Path locateCSVFile(String msg) throws IOException { JFileChooser fc = new JFileChooser(); File f = null; Path p = null; while (true) { int returnVal = fc.showDialog(null, msg); if (returnVal == JFileChooser.APPROVE_OPTION) { f = fc.getSelectedFile(); p = f.toPath(); if (Files.isRegularFile(p) && Files.isReadable(p) && (Files.probeContentType(p).equals("text/csv") || Files.probeContentType(p).equals("text/comma-separated-values") )) { return p; } JOptionPane.showMessageDialog(null, "Die Datei ist keine CSV Datei!"); } else break; } return null; } Seite 22 Texte analysieren – Beispiel CVS-Datei CSV-Datei einlesen : naive Analyse static List<Map<String, String>> readCSVFile(Path path, String seperator) throws IOException { // erste Zeile / Attribute String[] attributes = null; // alle Zeilen ausser der ersten List<Map<String, String>> res = new ArrayList<Map<String, String>>(); } boolean firstLine = true; // erste Zeile enthaelt Spalten- (=Attribut-) Namen for (String line : Files.readAllLines(path, Charset.defaultCharset())){ if (firstLine) { attributes = line.split(seperator); firstLine = false; continue; } Naive Analyse: CSV-Dateien können eine sehr komplexe Map<String,String> entry = new HashMap<>(); Struktur ausweisen, vor allem dann, wenn Zellen Werte String[] values = line.split(seperator); enthalten, in denen der Trenner vorkommt. int i = 0; for(String a: attributes) { String value = values[i].trim(); entry.put(a, value); i++; if (i == attributes.length || i == values.length) break; } res.add(entry); } return res; Excel speichert Tabellen in Binärformat. (Unterschiedlich mit den Versionen wechselnd, teilweise geheim.) Zum Lesen und Schreiben muss man dieses Format genau kennen. Die Java-API enthält keine entsprechenden Klassen. Man kann aber frei verfügbare Open-Source Bibliotheken verwenden, z.B.: Apache POI (http://poi.apache.org/). Seite 23 Dateien – Binär-Dateien Text-Dateien und Binär-Dateien alle Dateien enthalten Binärdaten! Textdatei enthält Bytes deren Bedeutung Zeichen sind Bedeutung der Bytes als Zeichen wird vom Zeichensatz (Charset) definiert Eingelesene Bytes müssen in programm-interne Zeichen umgewandelt werden Zeichen im Programm sind ebenfalls Bytes, aber meist nicht in der gleichen Codierung wie die vom Zeichensatz definierte Bitmuster A Lesen/Schreiben Umcodieren Bedeutet nach den Konventionen der Sprache Bedeutet im Zeichensatz cs Datei Bitmuster B Zeichen z Hauptspeicher / CPU Seite 24 Zeichensätze sind von großer Bedeutung Dateien – Binär-Dateien Text-Dateien und Binär-Dateien alle Dateien enthalten Binärdaten! Binärdatei Enthält Bytes deren Bedeutung von keiner Text-Konvention definiert ist Die Bedeutung der Bytes wird von der Anwendung definiert Eine Umwandlung der Bitmuster beim Lesen und Schreiben Findet nicht statt: Die Bitmuster werden so gespeichert, wie sie im Hauptspeicher zu finden sind Findet statt: Die Bitmuster werden beim Lesen decodiert und beim Schreiben codiert. Seite 25 Dateien – Binär-Dateien Binär-Dateien / Beispiel: Daten binär einlesen und ausgeben import import import import import import import import java.io.File; java.io.IOException; java.io.InputStream; java.io.OutputStream; java.nio.charset.Charset; java.nio.file.Files; java.nio.file.Path; java.nio.file.StandardOpenOption; import javax.swing.JFileChooser; import javax.swing.JOptionPane; public class ByteIO { public static void main(String[] args) throws IOException { Path pathI = ... Path pathO = ... InputStream is = Files.newInputStream(pathI, StandardOpenOption.READ); OutputStream os = Files.newOutputStream(pathO, StandardOpenOption.WRITE); byte[] bytes = new byte[1024]; int size = is.read(bytes); is.close(); // Bytes einlesen (maximal 1024 Bytes) // Bytes als entsprechend dem aktuellen Zeichensatz decodieren String s = new String(bytes, 0, size, Charset.defaultCharset()); System.out.println(s); os.write(bytes, 0, size); os.close(); // Bytes schreiben } } Seite 26 Dateien – Binär-Dateien Binär-Dateien / Serialisierung alle Dateien enthalten Binärdaten! Serialisierung / Deserialisierung Serialisieren: Die Bits von Objekten werden unverändert aus dem Hautspeicher in eine Datei geschrieben. Deserialisieren: Die Bits von Objekten werden unverändert von einer Datei in den Hauptspeicher kopiert Vorteil: Schnell Nachteil: Nicht Portabel, das Datenformat an Java gebunden Objekt Speicher 1 0 1 1 1 0 1 0 0 1 Seite 27 Datei Dateien – Binär-Dateien Binär-Dateien / Beispiel Serialisierung, Deserialisierung Markierung: Serialisieren erlaubt! Kontrolle der Version der Definition class Person implements Serializable { } private static final long serialVersionUID = 1L; private String name; private String vorName; public Person(String vorName, String name) { this.name = name; this.vorName = vorName; } @Override public String toString() { return "Person["+vorName+" "+name+"]"; } public static void main(String[] args) throws IOException, ClassNotFoundException { Person[] personen_1 = { new Person("Karl", "Napp"), new Person("Karla", "Kahl")}; Das zu speichernde Objekt (ein Path path = ... ObjectOutputStream os = new ObjectOutputStream( Files.newOutputStream(path, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)); os.writeObject(personen_1); os.close(); Datei öffnen Objekt speichern ObjectInputStream is = new ObjectInputStream( Files.newInputStream(path, StandardOpenOption.READ)); Person[] personen_2 = (Person[]) is.readObject(); is.close(); for (Person p: personen_2) { System.out.println(p); } } Seite 28 Datei öffnen Objekt einlesen Array) Dateien – Binär-Dateien Binär-Dateien / standardisierte Formate universelle Formate: z.B.: MP3 anwendungs-spezifische Formate, z.B. Speicherformat von Word, Excel „lokale“ Formate: Verabredung zwei Partner Vergleich zu Textdateien – Vorteil: Speicherung kompakter, schreiben / lesen schneller – Nachteil: schwer zu entziffern (kann auch Vorteil sein) Seite 29