1 1.Java 1.0 & 1.1 streams and classes 2.IO idioms 3. Object serialization
2 Stream = I/O abstraction -for any source (input) or sink (output) of data -hiding data handling in I/O device Java 1.0 Java 1.1 InputOutput Java 1.0 and 1.1 I/O systems not separate designs Both systems are used in parallel InputStream OutputStream Reader Writer
3 InputStream “Physical” source 1.Byte array (memory) 2.String object (memory) 3.File 4.Pipe (for interprocess/inter thread communication) 5.Sequence of streams 6.Others (e.g. internet connection – sockets) InputStream Application
4 InputStream 1.Byte array (memory) 2.String object (memory) 3.File 4.Pipe (for interprocess/inter thread communication) 5.Sequence of streams 6.Others (e.g. internet connection – sockets) InputStream StringBufferInputStream FileInputStream PipedInputStream SequenceInputStream ByteArrayInputStream InputStream has poor interface Usually wrapped in FilterInputStream-object !
5 FilterInputStream 1.DataInputStream - read primitive types (readXXX()) 2.BufferedInputStream- add buffering to InputStream 3.LineNumberInputStream- add line numbers to InputStream 4.PushbackInputStream- add push back buffer to InputStream 5.InflaterInputStream- decompress InputStream Inherits from InputStream ! All FilterInputStreams are decorators - ADD functionality, keep same interface - can be “concatenated” e.g. InputStream in + line numbers and reading primitives : DataInputStream d=new DataInputStream(new LineNumberInputStream(in));
6 Java1.0 Input classes Adaptation to physical devices InputStream StringBufferInputStream FileInputStream PipedInputStream SequenceInputStream ByteArrayInputStreamFilterInputStream DataInputStream BufferedInputStream LineNumberInputStream PushbackInputStream Decorators InflaterInputStream
7 OutputStream “Physical” destination 1.Byte array (memory) 2.File 3.Pipe (for interprocess/inter thread communication) 4.Others (e.g. internet connection – sockets) OutputStream Application
8 OutputStream 1.Byte array (memory) 2.File 3.Pipe (for interprocess/inter thread communication) 4.Others (e.g. internet connection – sockets) OutputStream FileOutputStream PipedOutputStream ByteArrayOutputStream OutputStream has poor interface Usually wrapped in FilterOutputStream-object !
9 FilterOutputStream 1.DataOutputStream - write primitive types (writeXXX()) (binary format – use with DataInputStream) 2.BufferedOutputStream- add buffering to OutputStream 3.PrintStream- add formatting to OutputStream (text format – for “display” human readable output) 4.DeflaterOutputStream- add compression to OutputStream Inherits from OutputStream ! Decorator pattern is used (again) e.g. OutputStream out + buffering + primitives DataOutputStream d = new DataOutputStream(new BufferedOutputStream(out));
10 Java1.0 Output classes Adaptation to physical devices OutputStream FileOutputStream PipedOutputStream ByteArrayOutputStreamFilterOutputStream DataOutputStream BufferedOutputStream PrintStream Decorators DeflaterOutputStream
11 A simple example Primitive output import java.io.*; import java.util.*; class PrimitiveIO { public static void main(String[] args) { int[] a={1,3,5,7}; try { writeInt(a,"Test.dat"); int[] b=readInt("Test.dat"); for(int i=0;i<b.length;i++) System.out.print("- "+b[i]); } catch(IOException e) { e.printStackTrace(); } public static void writeInt(int[] a,String n) throws IOException { DataOutputStream o=new DataOutputStream(new FileOutputStream(n)); for(int i=0;i<a.length;i++) o.writeInt(a[i]); o.close(); } //.. Continued … }
12 A simple example Primitive input class PrimitiveIO { // … continued … public static int[] readInt(String n) throws IOException { int[] res; ArrayList l=new ArrayList(); DataInputStream in=new DataInputStream(new BufferedInputStream( new FileInputStream(n))); try { while(true) l.add(new Integer(in.readInt())); } catch(EOFException e) { System.out.println("End of file reached !"); } finally { in.close(); } res=new int[l.size()]; for(int i=0;i<l.size();i++) res[i]=((Integer)(l.get(i))).intValue(); return res; }
13 Java1.1 Main changes/additions InputStream/OutputStream -> byte oriented (“pure binary”) new classes Reader/Writer -> char oriented (internationalization) support for object serialization provide bridges between Java1.0 and Java1.1 classes class for random access files Class hierarchy structure InputStreamReader InputStreamReader ObjectInputStream Java1.1 classes
14 Java1.1 : Reader Adaptation InputStream StringBufferInputStream FileInputStream PipedInputStream SequenceInputStream ByteArrayInputStream FilterInputStream Decorators DataInputStream BufferedInputStream LineNumberInputStream PushbackInputStream Adaptation Reader StringReader FileReader PipedReader CharArrayReader FilterReader Decorators BufferedReader LineNumberReader PushbackReader InputStreamReader ObjectInputStream byte oriented char oriented InflaterInputStream
15 Java1.1 : Writer Adaptation OutputStream Decorators ByteArrayOutputStream FileOutputStream PipedOutputStream DataOutputStream BufferedOutputStream PrintStream Adaptation Writer OutputStreamWriter Decorators CharArrayWriter FileWriter PipedWriter BufferedWriter PrintWriter StringWriter FilterWriter ObjectOutputStream byte oriented char oriented FilterOutputStream DeflaterOutputStream
16 The Java IO system OutputStreamWriter InputStreamReader RandomAccessFile adapt decorate bridge use char oriented classes when possible use byte oriented classes when necessary
17 Compression OutputStream FilterOutputStream DeflaterOutputStream ZipOutputStream GZIPOutputStream CheckedOutputStream InputStream FilterInputStream InflaterInputStream ZipInputStream GZIPInputStream CheckedInputStream
18 Read text lines from file class TextFileInput { public static void main(String[] args) { try { System.out.println(readTextFile("lines.txt")); } catch(IOException e) { System.err.println("IO Error !"); } public static String readTextFile(String n) throws IOException { BufferedReader in=new BufferedReader(new FileReader(n)); String s,res=""; while((s=in.readLine())!=null) res+=s+"\n"; in.close(); return res; } Use standard conversion methods to read primitives from text file : Integer.parseInt(s); Double.parseDouble(s); …
19 Read text lines from terminal import java.io.*; class TextTerminalInput { public static void main(String[] args) { try { System.out.println(readTextTerminal()); } catch(IOException e) { System.err.println("IO Error !"); } public static String readTextTerminal() throws IOException { BufferedReader in=new BufferedReader(new InputStreamReader(System.in)); String s,res=""; System.out.print("Input text line : "); while(!(s=in.readLine()).equals("")) { res+=s+"\n"; System.out.print("Input text line : "); } return res; } InputStream
20 Write text to file class TextFileOutput { public static void main(String[] args) { String[] t={"First line","Second line","Third line"}; try { writeTextFile("line.txt",t); } catch(IOException e) { System.err.println("IO Error !"); } public static void writeTextFile(String n,String[] s) throws IOException { PrintWriter out=new PrintWriter(new BufferedWriter(new FileWriter(n))); for(int i=0;i<s.length;i++) out.println(s[i]); out.flush(); // flush buffer out.close(); // close file }
21 Standard device redirection class RedirectOutput{ public static void main(String[] args) { try { System.setOut(new PrintStream( new BufferedOutputStream(new FileOutputStream(args[1])))); System.out.println(readTextFile(args[0])); System.out.close(); } catch(IOException e) { System.err.println("IO Error ! "+e); } // same as for reading text from file public static String readTextFile(String n) throws IOException { BufferedReader in=new BufferedReader(new FileReader(n)); String s,res=""; while((s=in.readLine())!=null) res+=s+"\n"; in.close(); return res; } System.setIn(InputStream) System.setOut(PrintStream) System.setErr(PrintStream)
22 Read text from memory class MemoryInput { public static void main(String[] args) { String mem="Read from memory !"; try { StringReader s=new StringReader(mem); int c; while((c=s.read())!=-1) System.out.print((char)c); } catch(IOException e) { System.err.println("Error in StringReader."); } byte[] b=mem.getBytes(); DataInputStream in=new DataInputStream(new ByteArrayInputStream(b)); System.out.println(""); try { while(in.available()!=0) System.out.print((char)in.readByte()); } catch(IOException e) { System.err.println("Error in ByteArrayInputStream."); } Memory buffer : byte[ ] Remaining number of bytes
23 Write binary to file class BinaryFileOutput { public static void main(String[] args) { try { DataOutputStream out=new DataOutputStream( new BufferedOutputStream(new FileOutputStream("data.txt"))); out.writeFloat(3.14f); out.writeDouble( ); out.writeChar('t'); out.writeChars("Some text"); out.close(); } catch(IOException e) { System.err.println("IO Error !"); }
24 Read binary from file class BinaryFileInput { public static void main(String[] args) { try { DataInputStream in=new DataInputStream( new BufferedInputStream(new FileInputStream("data.txt"))); System.out.println(in.readFloat()); System.out.println(in.readDouble()); System.out.println(in.readLine()); // deprecated API ! in.close(); } catch(IOException e) { System.err.println("IO Error !"); } t S o m e t e x t
25 Random access files unrelated to InputStream, OutputStream, Reader, Writer constructor : -file name -file mode : r [read only] rw [read and write] file pointer = index relative to file start (measured in bytes) can be retrieved by : long getFilePointer() moved by : void seek(long) standard methods to read/write readXXX: read primitive type writeXXX: write primitive type readUTF / write UTF: read/write String readLine: read String (line) read[Fully] / write[Fully]: read/write byte array
26 Random access files class RandomAccess { public static void main(String[] args) throws IOException { RandomAccessFile r=new RandomAccessFile("random.dat","rw"); for(int i=0;i<10;i++) r.writeDouble(i*1.111); for(int i=0;i<10;i+=2) { r.seek(i*8);// 8 bytes for 1 double r.writeDouble(i*1.1111); } // r.seek(10); // r.writeInt(8); r.seek(0); while(r.getFilePointer()<r.length()) { System.out.println(r.readDouble()); } r.close(); } without // with //
27 Serialization = transform object into “wire format” (= bit sequence) store entire object on file (portable binary format) => object can live beyond program termination “lightweight persistence” used for JavaBeans (Java component model) send object across network => application spread over multiple nodes distributed computing used for Remote Method Invocation (Java implementation of distributed objects)
28 Standard serialization class implements Serializable interface writing : create ObjectOutputStream (out) call out.writeObject( ) reading : create ObjectInputStream (in) call in.readObject() cast to specific class (result is of type Object) BUT : class file must be reachable by virtual machine !
29 Standard serialization class A implements Serializable { private int a=0; private double b=12.0; private String s="Some data"; public A() {System.out.println(" A() called.");} public A(int ia,double ib,String is) { a=ia;b=ib;s=is; } public void setA(int ia) {a=ia;} public void setB(double ib) {b=ib;} public void setS(String is) {s=is;} public String toString() { return "-> a="+a+" b="+b+" s="+s; }
30 Standard serialization class WriteObject { public static void main(String[] args) { ArrayList o; try {writeObjects("obj.dat"); } catch(IOException e) {System.err.println("Output Error : "+e); } try {o=readObjects("obj.dat"); for(int i=0;i<o.size();i++) System.out.println(o.get(i));// no casting needed for toString } catch(IOException e) { System.err.println("Input Error : "+e); } catch(ClassNotFoundException e) { System.err.println("Class Error : "+e); } public static void writeObjects(String n) throws IOException { ObjectOutputStream out=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(n))); A o1=new A(1,10.0,"First.");A o2=new A(2,20.0,"Second."); out.writeObject(o1);out.writeObject(o2);out.close(); } public static ArrayList readObjects(String n) throws IOException,ClassNotFoundException { ObjectInputStream in=new ObjectInputStream(new BufferedInputStream(new FileInputStream(n))); ArrayList l=new ArrayList(); try { while(true) l.add(in.readObject()); } catch(EOFException e) {System.err.println("End of file reached.");} in.close(); return l; } End of file reached. -> a=1 b=10.0 s=First. -> a=2 b=20.0 s=Second. NO CONSTRUCTGOR CALLS TO RESTORE OBJECT !
31 Standard serialization Statics class A implements Serializable { //.. Only changes shown … private static char c; public static void setC(char ic) {c=ic;} public String toString() { return "-> a="+a+" b="+b+" s="+s+" c = "+c; } public static void serializeStaticState(ObjectOutputStream o) throws IOException { System.out.println("serializeStaticState()."); o.writeChar(c); } public static void deserializeStaticState(ObjectInputStream i) throws IOException { System.out.println("deserializaStaticState()."); c=i.readChar(); } Statics not serialized ! IF needed : add custom static methods to serialize/deserialize static state provide explicit calls for serializing/deserializing static state
32 Standard serialization Statics class WriteObject { // … only changes shown … public static void writeObjects(String n) throws IOException { ObjectOutputStream out=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(n))); A o1=new A(1,10.0,"First.");A o2=new A(2,20.0,"Second."); A.setC('a'); out.writeObject(o1); out.writeObject(o2); A.serializeStaticState(out); A.setC('b'); out.close(); } public static ArrayList readObjects(String n) throws IOException,ClassNotFoundException { ObjectInputStream in=new ObjectInputStream(new BufferedInputStream(new FileInputStream(n))); ArrayList l=new ArrayList(); l.add(in.readObject()); A.deserializeStaticState(in); in.close(); return l; } serializeStaticState(). deserializaStaticState(). -> a=1 b=0.0 s=First. c = a -> a=2 b=0.0 s=Second. c = a
33 Aggregating serializables class A implements Serializable { private int a=0; private double b=12.0; private String s="Some data"; private B myB; public A() {System.out.println(" A() called.");} public A(int ia,double ib,String is,B aB) { a=ia;b=ib;s=is;myB=aB; } public void setA(int ia) {a=ia;} public void setB(double ib) {b=ib;} public void setS(String is) {s=is;} public String toString() { return "-> a="+a+" b="+b+" s="+s+myB; } class B implements Serializable { // MUST BE SERIALIZABLE ! private int c=0; public B() {System.out.println(" B() called.");} public B(int i) {c=i;}; public void setC(int ic) {c=ic;}; public String toString() { return "\t c="+c; }
34 Aggregating serializables // … rest the same … public static void writeObjects(String n) throws IOException { ObjectOutputStream out=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(n))); A o1=new A(1,10.0,"First.",new B(100)); A o2=new A(2,20.0,"Second.",new B(200)); out.writeObject(o1); out.writeObject(o2); out.close(); } // … End of file reached. -> a=1 b=10.0 s=First. c=100 -> a=2 b=20.0 s=Second. c=200 Serialization mechanism follows the “web of objects”
35 Transient fields Do not serialize some fields : some objects can not be serialized (e.g. Thread objects) not logical to store permanently (e.g. password field) Mark fields as “transient” class A implements Serializable { private int a=0; private transient double b=12.0; private String s="Some data"; private transient B myB;// B not necessarily Serializable ! public A() {System.out.println(" A() called.");} public A(int ia,double ib,String is,B aB) { a=ia;b=ib;s=is;myB=aB; } public void setA(int ia) {a=ia;} public void setB(double ib) {b=ib;} public void setS(String is) {s=is;} public String toString() { return "-> a="+a+" b="+b+" s="+s+myB; } End of file reached. -> a=1 b=0.0 s=First.null -> a=2 b=0.0 s=Second.null
36 Customized serialization Empty interface Custom serialization
37 Customized serialization class A implements Externalizable { private int a=0; private double b=12.0; private String s="Some data"; public A() {System.out.println(" A() called.");} public A(int ia,double ib,String is) {a=ia;b=ib;s=is;} public void setA(int ia) {a=ia;} public void setB(double ib) {b=ib;} public void setS(String is) {s=is;} public String toString() {return "-> a="+a+" b="+b+" s="+s;} public void writeExternal(ObjectOutput o) throws IOException{ System.out.println("writeExternal()."); // super.writeExternal(o); o.writeInt(a);o.writeDouble(b);o.writeObject(s); } public void readExternal(ObjectInput i) throws IOException,ClassNotFoundException { System.out.println("readExternal()."); // super.readExternal(i); a=i.readInt();b=i.readDouble();s=(String)i.readObject(); } writeExternal(). A() called. readExternal(). A() called. readExternal(). End of file reached. -> a=1 b=10.0 s=First. -> a=2 b=20.0 s=Second. default constructor called ! (must be reachable !)
38 “TRICKY” Customized serialization Customized serialization WITHOUT implementing Externalizable implement Serializable ADD (NOT override !) following methods : private void writeObject(ObjectOutputStream o) throws IOException private void readObject(ObjectInputStream i) throws IOException customization options : full customization variation on standard serialization : use default methods o.defaultWriteObject() i.defaultReadObject() this type of design can NOT be achieved in standard JAVA !
39 “TRICKY” Customized serialization class A implements Serializable { private int a=0; private transient double b=12.0; private String s="Some data"; public A() {System.out.println(" A() called.");} public A(int ia,double ib,String is) { a=ia;b=ib;s=is; } public void setA(int ia) {a=ia;} public void setB(double ib) {b=ib;} public void setS(String is) {s=is;} public String toString() { return "-> a="+a+" b="+b+" s="+s; } private void writeObject(ObjectOutputStream o) throws IOException{ System.out.println("writeObject()."); o.defaultWriteObject(); o.writeDouble((b<15.0) ? 0.0 : 100.0); } private void readObject(ObjectInputStream i) throws IOException,ClassNotFoundException { System.out.println("readObject()."); i.defaultReadObject(); b=i.readDouble(); } writeObject(). readObject(). End of file reached. -> a=1 b=0.0 s=First. -> a=2 b=100.0 s=Second.
40 Inheritance class A implements Serializable { private int a=0; public A() {System.out.println(" A() called.");} public A(int ia) {a=ia;} public void setA(int ia) {a=ia;} public String toString() {return super.toString()+"-> a="+a;} } class B extends A { private int b=0; public B() {System.out.println(" B() called.");} public B(int ia,int ib) {super(ia);b=ib;}; public void setB(int ib) {b=ib;}; public String toString() {return super.toString()+"\t b="+b;} } class Serial1 { // methods main and readObjects same as before public static void writeObjects(String n) throws IOException { ObjectOutputStream out=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(n))); A o1=new A(1); B o2=new B(2,20); System.out.println(o1);System.out.println(o2); out.writeObject(o1);out.writeObject(o2); out.close(); } a=1 a=2 b=20 End of file reached. a=1 a=2 b=20 no constructor calls objects retrieved, stored at different location
41 Inheritance class A { // same as before } class B extends A implements Serializable { // same as before } class Serial2 { // main and readObjects same as before public static void writeObjects(String n) throws IOException { ObjectOutputStream out=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(n))); B o2=new B(2,20); System.out.println(o2); out.writeObject(o2); out.close(); } a=2 b=20 A() called. End of file reached. a=0 b=20 No-arg constructor called for unserializable base object Only serializable part stored to and retrieved from stream
42 Inheritance class A implements Externalizable { // same as before + public void writeExternal(ObjectOutput o) throws IOException { System.out.println("A.writeExternal()."); o.writeInt(a); } public void readExternal(ObjectInput i) throws IOException { System.out.println("A.writeExternal()."); a=i.readInt(); } class B extends A { // same as before + public void writeExternal(ObjectOutput o) throws IOException { System.out.println("B.writeExternal()."); super.writeExternal(o); o.writeInt(b); } public void readExternal(ObjectInput i) throws IOException { System.out.println("B.writeExternal()."); super.readExternal(i); b=i.readInt(); }
43 Inheritance class Serial3 { // main and readObjects same as before public static void writeObjects(String n) throws IOException { ObjectOutputStream out=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(n))); A o1=new A(1); B o2=new B(2,20); System.out.println(o1);System.out.println(o2); out.writeObject(o1);out.writeObject(o2);out.close(); } a=1 a=2 b=20 A.writeExternal(). B.writeExternal(). A.writeExternal(). A() called. A.writeExternal(). A() called. B() called. B.writeExternal(). A.writeExternal(). End of file reached. a=1 a=2 b=20 call super-methods to store/retrieve base object (especially if private members …) retrieving Externalizables ALWAYS calls constructor !
44 Aggregation class A implements Serializable { // clone method added to A public Object clone() {return new A(a);} } class Serial4 { // main and readObjects unchanged public static void writeObjects(String n) throws IOException { ObjectOutputStream out=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(n))); A o1=new A(1); System.out.println(o1); out.writeObject(o1); // out.close(); // out=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(n))); o1.setA(10); System.out.println(o1); out.writeObject(o1); A o2=(A)o1.clone(); System.out.println(o2); out.writeObject(o2); out.close(); } a=1 a=10 a=10 End of file reached. a=1 a=10 with // a=1 a=10 a=10 End of file reached. a=10 a=10 without // Serialization (to same stream !) avoids unnecessary (and dangerous) duplicates Updates are unsafe !
45 Aggregation class A implements Serializable { private int a=0; private B b; public A() {System.out.println(" A() called.");} public A(int ia,B ib) {a=ia;b=ib;} public void setA(int ia) {a=ia;} public B getB() {return b;} public String toString() { return super.toString()+"-> a="+a+b; } public Object clone() {return new A(a,(B)b.clone());} } class B implements Serializable { private int b=0; public B() {System.out.println(" B() called.");} public B(int ib) {b=ib;}; public void setB(int ib) {b=ib;}; public String toString() { return "\t"+super.toString()+" b="+b; } public Object clone() {return new B(b);} }
46 Aggregation class Serial5 { // main and readObjects unchanged public static void writeObjects(String n) throws IOException { ObjectOutputStream out=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(n))); B b1=new B(10); B b2=new B(20); A a1=new A(1,b1); //A a2=new A(2,b2); //[1] //A a2=new A(2,(B)b1.clone());//[2] A a2=new A(2,b1);//[3] System.out.println(a1); System.out.println(a2); out.writeObject(a1); out.writeObject(a2); out.close(); } a=1 b=10 a=2 b=20 End of file reached. a=1 b=10 a=2 b=20 with [1] a=1 b=10 a=2 b=10 End of file reached. a=1 b=10 a=2 b=10 Serialization maintains “web of object logic” a=1 b=10 a=2 b=10 End of file reached. a=1 b=10 a=2 b=10 with [2] with [3]
47 Aggregation // main and readObjects unchanged public static void writeObjects(String n) throws IOException { ObjectOutputStream out=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(n))); B b=new B(10); A a1=new A(1,b); A a2=new A(2,b); System.out.println(a1); out.writeObject(a1); b.setB(100); System.out.println(a2); out.writeObject(a2); out.close(); } a=1 b=10 a=2 b=100 End of file reached. a=1 b=10 a=2 b=10
48 Aggregation // main unchanged public static void writeObjects(String n) throws IOException { ObjectOutputStream out=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(n))); B b=new B(10); A a1=new A(1,b); A a2=new A(2,b); System.out.println(a1); out.writeObject(a1); System.out.println(a2); out.writeObject(a2); out.close(); } public static ArrayList readObjects(String n) throws IOException,ClassNotFoundException { ObjectInputStream in=new ObjectInputStream(new BufferedInputStream(new FileInputStream(n))); ArrayList l=new ArrayList(); A a1=(A)in.readObject(); a1.getB().setB(100); A a2=(A)in.readObject(); l.add(a1); l.add(a2); in.close(); return l; } a=1 b=10 a=2 b=10 a=1 b=100 a=2 b=100
49 Conclusion 3 options to serialize implement Serializable (some customization possible using “transient”) implement Externalizable (full customization necessary) use trick with Serializable Serialization is not identical to writing to standard stream web of objects is maintained changes to objects while stream is open : considered unsafe Advice : consider serialization “Atomic” collect all related objects in 1 collection store/retrieve in 1 serialization operation