Dateien/Streams Arthur Zaczek Okt 2015 Dateien/Streams 1 Input/Output 1.1 Was ist ein Stream? Figure 1: InputStream Figure 2: OutputStream Graphik: (C) Copyright 1995-2009 Sun Microsystems, Inc. 1.2 Warum streamen? • Reduktion des Speicherverbrauchs: es muss nicht der gesamte Input auf einmal im RAM sein • Überlappung von Übertragung und Verarbeitung: – “pipelined requests” bei HTTP – inkrementelle Verarbeitung von XML(“SAX”) 1.3 Primitiv: Byte-Streams • Notwendig für Kommunikation mit Außenwelt: – Dateien – Netzwerk C# 1 Dateien/Streams • System.IO.Stream.FileStream • System.Net.Sockets.NetworkStream Java • System.IO.Stream.FileStream • java.net.Socket – .getInputStream() – .getOutputStream() 1.4 Byte-Stream in C public class Stream { int ReadByte(); void WriteByte(byte value); int Read(byte[] buffer,int offset, int count); void Write(byte[] buffer,int offset, int count) long Seek(long offset,SeekOrigin origin); bool CanRead, CanWrite, CanSeek; } 1.5 Byte-Streams in Java public class java.io.InputStream { int read(); int read(byte[] buffer); int read(byte[] buffer,int offset, int length); long skip(long count); boolean markSupported(); void mark(int readLimit); void reset(); } public class java.io.OutputStream { void write(int b); void write(byte[] data); void write(byte[] data,int offset, int length); } 1.6 Datei öffnen für Lesen: C using (FileStream fs = File.OpenRead(path)) { // byte Buffer, Ziel für eingelesene Daten byte[] b = new byte[1024]; while (fs.Read(b, 0, b.Length) > 0) { // dekodiert 1024 Bytes in 256 Zeichen; das funktioniert // natürlich nur für Encodings mit konstanter Breite Console.WriteLine(Encoding.UTF32.GetString(b)); 2 Dateien/Streams } } // fs wird automatisch von "using" geschlossen 1.7 Datei öffnen für Schreiben: Java try (FileOutputStream fs = new FileOutputStream(path)) { fs.write(data); // Bytearray mit kodierten Daten } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // fs.close() wird automatisch von "try ()" aufgerufen 1.8 Text I/O • Text besteht nicht aus Bytes sondern aus Chars (zB UTF-8) • daher: I/O in Bytes nur Mittel zum Zweck • Kodierung und Dekodierung über Wrapperstreams: – C#: TextReader/-Writer – Java: Reader/Writer 1.9 TextReader und -Writer in CS public class TextReader { char Read(); int Read(char[] buffer,int offset, int count); string ReadLine(); } public class TextWriter { void Write( bool/char/char[]/decimal/double/int/Int64/object/float/string/uint/UInt64); void WriteLine(--"--); } 1.10 Implementierungen in CS • StringReader/Writer: string test = "Fix, Schwyz! quäkt Jürgen vom Paß"; TextReader reader = new StringReader(test); reader.ReadLine() == test; TextWriter writer = new StringWriter(); writer.WriteLine(test); writer.ToString() == test; • Dateien: TextReader reader = new StreamReader(File.OpenRead (path)); TextWriter writer = new StreamWriter(File.Open(path)); 3 Dateien/Streams 1.11 (Text) Reader und Writer in Java public class java.io.Reader { int read(); int read(char[] buffer); int read(char[] buffer,int offset, int length); long skip(long count); boolean markSupported(); void mark(int readLimit); void reset(); } public class java.io.Writer { void write(int c); void write(char[] data); void write(char[] data, int offset, int length); void write(String data); void write(String data, int offset, int length); } 1.12 Implementierungen in Java • StringReader/Writer Reader reader = new StringReader(sourceString); Writer writer = new StringWriter(); String result = writer.toString() • FileReader/Writer Reader reader = new FileReader(path); Writer writer = new FileWriter(path); 1.13 Binärdaten lesen/schreiben • Effizient: interne Repräsentierung (Bitmuster) kann direkt gelesen/geschrieben werden. Keine Konversion notwendig • unportabel: interne Repräsentierung eben “intern” • unsicher: Stream enthält keine Typinformation, keine Checksummen, keine Begin/Endemarker, beim Lesen muss man wissen was man erwartet • intransparent: Binäre Repräsentation nicht durch einfaches Anschauen lesbar 1.14 BinaryReader/-Writer in CS public class BinaryReader { bool ReadBoolean(); byte ReadByte(); short/int/long ReadInt16/32/64(); float/double ReadSingle/Double(); string ReadString(); // ... 4 Dateien/Streams } public class BinaryWriter { void Write( bool/byte/short/int/long/float/ double/string/...); } 1.15 Implementierung in CS using(var writer = new BinaryReader(File.Open(path))) { writer.WriteBoolean(true); writer.WriteDouble(2000.3); writer.WriteString("Schwyz!"); } using(var reader = new BinaryReader(File.OpenRead (path))) { bool someBool = reader.ReadBoolean(); float someFloat = reader.ReadFloat(); // schwerer Fehler! string someString = reader.ReadString(); } 1.16 DataInput/-Output in Java public class DataInput { boolean readBoolean(); byte readByte(); short/int/long readShort/Int/Long(); float/double readFloat/Double(); String readUTF(); // ... } public class DataOutput { void WriteBoolean/Byte/Short/Int/Long/ Float/Double/UTF( boolean/int/short/int/long/float/ double/string/...); } 1.17 Implementierung in Java try (DataOutputStream writer = new DataOutputStream(new FileOutputStream(path))) { writer.writeBoolean(true); writer.writeDouble(2000.3); writer.writeString("Schwyz!"); } 1.18 Puffern in Strömen • Normalerweise verursacht jeder read()/write() einen Aufruf auf dem zugrundeliegenden Speichermedium 5 Dateien/Streams • je kleiner die Anfragen (zB zeichenweise mit ReadChar()) desto ineffizienter • Die Buffered* Varianten hingegen lesen immer von einem Stream und immer in “großen” Stücken (zB Java standardmäßig 8kB) wesentlich höherer Durchsatz, dafür auch mehr Speicherverbrauch 1.19 Dateinamenverwaltung: CS • DriveInfo.GetDrives(): Liste aller Laufwerke • Path.Combine(driveinfo.Name, "foo", "blah"): “D:\foo\blah” auf Windows Desktop, möglicherweise “/home/foo/blah” auf mono/Linux • Path.GetFullPath("blah"): absoluter Pfad 1.20 • • • • 1.21 Dateinamenverwaltung: Java File.listRoots(): Liste aller Laufwerke new File(file, "blah"): “D:\blah” auf Windows, möglicherweise “/. . . /blah” auf Linux file.getAbsolutePath(): absoluter Pfad file.getCanonicalPath(): “Standardversion” eines Pfades (ohne Symlinks, “.” und “..”) Kurze Demo Java, C# 6