170 likes | 185 Views
Learn about Java I/O streams, including the concept of streaming, input and output streams, byte-oriented and char-oriented classes, file handling, and the Decorator design pattern. Explore different classes and their functionalities.
E N D
Algorithm Programming 189-210 I/O via Java Streams Bar-Ilan University 2007-2008 תשס"ח by Moshe Fresko
Java I/O Streams • Java I/O uses abstraction of “streaming” concept • Stream : Abstract Representation of an Input/Output device, that is source of, or destination of data. • Input stream : To read data from. • Output stream : To write data to. • In library java.io.* we have two sets of I/O classes • Byte Oriented classes • The Abstract Classes are: • InputStream • OutputStream • Char Oriented classes (16 bit Unicode) • The Abstract Classes are: • Reader • Writer
Defining a File • java.io.File class : An abstract representation of file or directory pathnames. • File(String pathname) • … • String getAbsolutePath() • String getPath() • String getName() • … • boolean exists() • boolean canRead() • boolean canWrite() • … • boolean createNewFile() • boolean mkdir() • boolean delete() • etc.
Java Byte Oriented I/O • Byte based Abstract I/O Classes • java.io.InputStream • InputStream() • int read() throws IOException • int read(byte[] dest) throws IOException • int read(byte[] dest, int offset, int length) throws IOException • void close() throws IOException • int available() throws IOException • long skip(long nbytes) throws IOException • boolean markSupported() • void mark(int readlimit) • void reset() throws IOException • java.io.OutputStream • OutputStream() • void write(int b) throws IOException • void write(byte[] b) throws IOException • void write(byte[] b, int offset, int length) throws IOException • void flush() throws IOException • void close() throws IOException
DECORATOR pattern • We want to define an abstract Food class (or a Food Interface) to represent any food that can be sold in a Pizza shop. Let’s look to the following design … interface Food { float getPrice() ; String getDescription() ; } class Pizza implements Food { float getPrice() { return 50 ; } String getDescription() { return “Regular Pizza” ; } } class PizzaWithOnion extends Pizza // Adds 5 shekels { float getPrice() { return super.getPrice()+5 ; } String getDescription() { return super.getDescription() + “ with Onion” ; } }
DECORATOR pattern class PizzaWithCorn extends Pizza { // Adds 7 shekels … } class PizzaWithOnionAndCorn extends Pizza { // Adds 12 shekels … } // Etc. … // In the program Food f = new PizzaWithOnionAndCorn() ; … System.out.println(“You bought : “+f.getDescription()) ; System.out.println(“Price in Shekels is : “+f.getPrice()) ; …
DECORATOR pattern • Problems: • Many classes have to be defined… (For all the combinations) • What if Corn’s price will rise from 7 shekels to 8 shekel ? • What if we have another addition, let’s say “Tuna Fish” ?
DECORATOR pattern • Alternative design with “Decorator” pattern interface Food { float getPrice() ; String getDescription() ; } class Pizza implements Food { float getPrice() { return 50 ; } String getDescription() { return “Regular Pizza” ; } } class Addition implements Food { Food f ; Addition(Food f) { this.f = f ; } float getPrice() { return f.getPrice() ; } String getDescription() { return f.getDescription() ; } }
DECORATOR pattern class PlusOnion extends Addition { PlusOnion(Food f) { super(f) ; } float getPrice() { return super.getPrice() + 5 ; } String getDescription() { return super.getDescription() + “, with Onion”); } } class PlusCorn extends Addition { PlusCorn(Food f) { super(f) ; } float getPrice() { return super.getPrice() + 7 ; } String getDescription() { return super.getDescription() + “, with Corn”); } } // Etc. … // In the program Food f = new PlusOnion(new PlusCorn(new Pizza())) ; … System.out.println(“You bought : “+f.getDescription()) ; System.out.println(“Price in Shekels is : “+f.getPrice()) ;
DECORATOR pattern • The use of layered objects to dynamically and transparently add responsibilities to individual objects is referred to as the “decorator” pattern. • Some properties • Used when sub-classing creates too many (and inflexible) classesMore flexible then static inheritance • All decorators that wrap around the original object must have the same basic interface • Changing the skin (vs. changing functionality internals like in Strategy) • Component classes must be lightweight • We can omit abstract decorator if we have only one decorator • Tradeoff: a. Coding is more complicated when using decoratorsb. A decorator and its component aren’t identicalc. Lots of little objects • Decorator classes can add functionality
Java Byte Oriented I/O classes • “InputStream” classes • FileInputStream : Reads from a file • ByteArrayInputStream : Reads from a byte-array • StringBufferInputStream : Reads from a String • PipedInputStream : Reads from another output pipe • SequenceInputStream : Reads from two or more “InputStreams” sequentially • FilterInputStream : As a “DECORATOR” abstract class • DataInputStream : To Read Primitive Data Types. readInt(), readByte() • BufferedInputStream : Adds buffering • LineNumberInputStream : Counts the number of lines • PushbackInputStream : Can push-back a character • “OutputStream” classes • FileOutputStream • ByteArrayOutputStream • PipedOutputStream • FilterOutputStream • DataOutputStream • PrintStream • BufferedOutputStream
Input Stream Definition // As it is defined in Java public abstract class InputStream { // ... public abstract int read() throws IOException; public int read(byte b[]) throws IOException { return read(b, 0, b.length); } public int read(byte b[], int off, int len) throws IOException { // ... } // ... public void close() throws IOException { } // ... }
Filter Input Stream Definition // As it is defined in Java public class FilterInputStream extends InputStream { protected InputStream in; protected FilterInputStream(InputStream in) { this.in = in; } public int read() throws IOException { return in.read(); } public int read(byte b[]) throws IOException { return read(b, 0, b.length); } public int read(byte b[], int off, int len) throws IOException { return in.read(b, off, len); } public void close() throws IOException { in.close(); } // ... }
I/O Examples import java.io.* ; public class FileCopy { // Copies one file to another public static void main(String[] args) throws IOException { if (args.length<2) { System.out.println("arguments: SourceFile DestFile") ; System.exit(1) ; } InputStream in=new BufferedInputStream( new FileInputStream(args[0])); OutputStream out=new BufferedOutputStream( new FileOutputStream(args[1])); int next ; while((next=in.read())>=0) out.write(next) ; in.close() ; out.close() ; } }
Char based I/O Classes • Unicode Char based Abstract I/O Classes • java.io.Reader • Reader() • Reader(Object lock) • int read() throws IOException • int read(char[] dest) throws IOException • int read(char[] dest, int offset, int length) throws IOException • void close() throws IOException • long skip(long nchars) throws IOException • boolean markSupported() • void mark(int readlimit) • void reset() throws IOException • void ready() throws IOException • java.io.Writer • Writer() • Writer(Object lock) • void write(int c) throws IOException • void write(char[] b) throws IOException • void write(char[] c, int offset, int length) throws IOException • void write(String s) throws IOException • void write(byte[] c, int offset, int length) throws IOException • void flush() throws IOException • void close() throws IOException
I/O Examples import java.io.* ; class DoubleTheNumber { public static void main(String args[]) throws IOException { BufferedReader br = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Enter a number:") ; String s = br.readLine() ; int i=Integer.parseInt(s) ; i*=2 ; System.out.println("Twice this much is:"+i) ; } }