860 likes | 1.27k Views
Lecture 6. Java I/O. Cheng-Chia Chen. Contents. Overview of I/O Streams Using the Data Sink Streams How to Use File Streams How to Use Pipe Streams Using the Processing Streams How to Concatenate Files Working with Filtered Streams How to Use DataInputStream and DataOutputStream
E N D
Lecture 6. Java I/O Cheng-Chia Chen
Contents • Overview of I/O Streams • Using the Data Sink Streams • How to Use File Streams • How to Use Pipe Streams • Using the Processing Streams • How to Concatenate Files • Working with Filtered Streams • How to Use DataInputStream and DataOutputStream • Writing Your Own Filtered Streams • Object Serialization • Serializing Objects • Providing Object Serialization for Your Classes • Working with Random Access Files • Using Random Access Files • Writing Filters for Random Access Files
I/O Streams • A stream is a sequence of bytes (or data or objects) that flow from a source to a destination • In a program, we read information from an input stream and write information to an output stream for output for input
procedure for reading/writing data to/from an input/output stream • general program schema for for reading and writing data from/to an Input/output stream: • // for reading: • 1.open an input stream // open • 2. while there is more information // reading • read next data from the stream • 3. close the stream. // close • // for writing • 1. open an output stream // open • 2. while there is more information // writing • write data to the stream • 3. close the stream. // close
I/O Stream Categories • The java.io package contains many classes that allow us to define various streams with specific characteristics • The classes in the I/O package divide input and output streams into other categories • An I/O stream is either a • character stream, which deals with text data • byte stream, which deal with byte data • An I/O stream is also either a • data stream, which acts as either a source or destination • processing stream, which alters or manages information in the stream
classification of Java I/O streams and their naming conventions • By I/O Directions: • for Input => Input • for output => Output • By datatype of stream content • char data => Reader / Writer • byte data => InputStream / OutputStream • other primitive data(int, long, float,…) => DataInputStream /DataOutputStream • Objects => ObjectInputStream /ObjectOutputStream • By characteristic of stream source / destination • 1. for final device : data sink stream • file,byte/char array, StringBuffer, pipe • purpose: serve as the source/destination of the stream. • 2. for intermediate process : processing streams • Buffering, Filtering, Byte2Char, Char2Byte, etc. • purpose: alters or manages information in the stream
The java.io package InputStream OutputStream Reader Writer
java.io.InputStream and its subclasses • gray => data sink stream • white => processing stream // require other streams
Basic methods provided in java input classes • Reader and InputStream define similar APIs but for different data types. • Reader contains methods for reading characters and arrays of characters: • int read() • int read(char cbuf[]) • int read(char cbuf[], int offset, int length) • InputStream defines the same methods but for reading bytes and arrays of bytes: • int read() • int read(byte cbuf[]) • int read(byte cbuf[], int offset, int length) • Both classes provide methods for marking a location in the stream, skipping input, and resetting the current position.
Basic methods provided in java output streams • Writer defines these methods for writing character, string and arrays of characters • void write(int c) // 16 low-ordered bits of c is written • void write(char[] cbuf [, int off, int len ] ) • void write(String s [, int off, int len ] ) • OutputStream defines the same methods but for bytes: • void write(int c) // 8 low-ordered bits of c is written • void write(byte cbuf[]) • void write(byte cbuf[], int offset, int length) • All of the streams--readers, writers, input streams, and output streams— • are automatically opened when created ! • can be closed by calling its close() method, or the garbage collector. • will throw IOException on failure of IO operations.
Standard I/O • There are three standard I/O streams: • standard input– defined by System.in • standard output– defined by System.out • standard error– defined by System.err • We use System.out when we execute println statements • System.out and System.err are of the type PrinterStream. • System.in is declared to be a generic InputStreamreference, and therefore usually must be mapped to a more useful stream with specific characteristics • eg: to read char instead of bytes => • InputStreamReader cin = new InputStreamReader(System.in);
java.io.InputStream • public abstract class InputStream extends Object Constructor : • InputStream() // default no-arg constuctor Method Summary • int available() • Returns the number of bytes that can be read (or skipped over) from this input stream without blocking by the next read(…) . • void close() • Closes this input stream and releases any system resources associated with the stream. • abstract int read( [ byte[] b [, int offset, int length ]] ) • Reads the next byte of data from the input stream. • Reads some number of bytes from the input stream and stores them into the buffer array b. • long skip(long n) • Skips over and discards n bytes of data from this input stream.
Methods for marking operaqtions • voidmark(int readlimit) • Marks the current position in this input stream. • readlimit is the number of bytes that can be read without invalidating this mark operation. • void reset() • Repositions this stream to the position at the time the mark method was last called on this input stream. • boolean markSupported() • Tests if this input stream supports the mark and reset methods.
java.io.Reader • public abstract class Reader extends Object • Abstract class for reading character streams. • The only methods that a subclass must implement are read(char[], int, int) and close(). • Most subclasses, however, will override some of the methods defined here in order to provide higher efficiency, additional functionality, or both. Field Summary • protected Object lock • The object used to synchronize operations on this stream. • use lock instead of this or synchronized method for efficient time-critical operations Constructor Summary • protected Reader() • Create a new character-stream reader whose critical sections will synchronize on the reader itself. • protected Reader(Object lock) • Create a new character-stream reader whose critical sections will synchronize on the given object.
Methods summary of java.io.Reader • abstract void close()// Close the stream. • int read() // Read a single character. • int read(char[] cbuf [,int off, int len] ) • Read characters into an array. • boolean ready() // replacement of available() in java.InputStream • Tell whether this stream is ready to be read • [ without causing I/Oblocking in next read()]. • long skip(long n) // Skip characters. • void mark(int limit) • Mark the present position in the stream. limit is the number of chars that can be read without causing failure of the following reset(). • void reset() // Reset the stream. • boolean markSupported() • Tell whether this stream supports the mark() operation.
Java.io.OutputStream • public abstract class OutputStream extends Object • the superclass of all classes representing an output stream of bytes. • An output stream accepts output bytes and sends them to some sink. • Subclasses must always provide at least a method that writes one byte of output. Constructor Summary • OutputStream()// will automatically open this stream for writing Methods summary • void close() // Closes this output stream and releases system resources. • void flush() • Flushes this output stream and forces any buffered output bytes to be written out. • void write(byte[] b, int off, int len) • Writes len bytes from the specified byte array starting at offset off to this output stream. • abstract void write( int b) // Writes the specified byte to this output stream.
java.io.Writer • public abstract class Writer extends Object • Abstract class for writing to character streams. • Subclass must implement write(char[], int, int), flush(), and close(). • subclasses may override some of the methods defined here in order to provide higher efficiency, additional functionality, or both. • Field Summary • protected Object lock • The object used to synchronize operations on this stream. • Constructor Summary • protected Writer() • Create a new character-stream writer whose critical sections will synchronize on the writer itself. • protected Writer(Object lock) • Create a new character-stream writer whose critical sections will synchronize on the given object.
java.io.Writer method summary • abstract void close() // Close the stream, flushing it first. • abstract void flush() // Flush the stream. • abstract void write(char[] cbuf, int off, int len) • Write a portion of an array of characters. • void write(int c) // Write a single character. • void write(String str) // Write a string. • void write(String str, int off, int len) • Write a portion of a string.
JDK1.3 ‘s implementation of write( int ) protected Object lock; // for synchronization private char[] writeBuffer; // for chars to be output private final int writeBufferSize = 1024; public void write( int c) throws IOException { synchronized (lock) { if (writeBuffer == null){ writeBuffer = new char[writeBufferSize]; } writeBuffer[0] = (char) c; write(writeBuffer, 0, 1); } } • Subclasses that intend to support efficient single-character output should override this method.
2. The Data Sink Streams • Types of data sinks: memory[array, strings], files, or pipes • Naming convention: <sinkType><I/O;CharOrByte>
Summary of the data sink streams • FileReader, FileWriter; FileInputStream, FileOutputStream • Collectively called file streams; used to read from or write to a file on the native file system. • CharArrayReader, CharArrayWriter; ByteArrayInputStream, ByteArrayOutputStream • Use these streams to read from and write to memory array. • create these streams on an existing array and then use the read and write methods to read from or write to the array. • Constructors: <Type> = new <Type>( {char | byte } [] [, int offset, int length ] ) • Ex: CharArrayWriter cwr = new CharArrayWriter( new char[100] ) ; • ByteArrayInputstream bi = new ByteArrayInputStream • ( new byte[] {\011,\022, \0xff} );
String Streams • StringReader, StringWriter, StringBufferInputStream • StringReader : used to read characters from a String. • StringWriter : used to to write to a String. StringWriter collects the characters written to it in a implicit StringBuffer, which can then be converted to a String. • StringBufferInputStream : similar to StringReader, except that it reads bytes from a StringBuffer. (deprecated since it cannot correctly convert a char to bytes; use StringReader instead) • Constructors: • StringReader(String); • StringWriter( [int initSize] ) // initial buffer size use toString() to get the written String • StringBufferInputStrean(String) // deprecfated ! Only the low eight bitsof each character in the string are used by this class.
Piped Streams • PipedReader, PipedWriter; • PipedInputStream, PipedOutputStream • Implement the input and output components of a pipe. • Pipes are used to channel the output from one program (or thread) into the input of another. • PipedReader and PipedInputStream get data from the output of another thread, while PipedWriter and PipedOutputStream output data for processing by other thread.
2.1 How to Use File Streams • File streams are the easiest streams to understand. • Create (and open )the file stream: • <FileStream> f = new <FileStream>( <file> ); • where <FileStream> is any of FileReader, FileWriter, FileInputStream, and FileOutputStream and • <file> is either a string for file name, a File object, or a FileDescriptor object (low-level handle to open file or socket). • EX: • FileReader reader1 = new FileReader(“example1.txt”); • File file1 = new File(“d:\\java\\examples\\ex1.java”); • FilerWriter writer1 = new FileWriter(file1); • FileInputStream in1 = new FileInputStream(“ex2”); • FileOutputStream out1 = new FileOutputStream ( java.io.FileDescriptor.out );
A simple file-copy program • Copy the contents of a file named input.txt into a file called output.txt: import java.io.*; public class Copy { public static void main(String[] args) throws IOException { File inputFile = new File(“input.txt"); File outputFile = new File("output.txt"); FileReader in = new FileReader( inputFile ); FileWriter out = new FileWriter( outputFile ); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); } }
Copy bytes import java.io.*; public class CopyBytes { public static void main(String[] args) throws IOException { File inputFile = new File(“input.txt"); File outputFile = new File("output.txt"); FileInputStream in = new FileInputStream(inputFile); FileOutputStream out = new FileOutputStream(outputFile); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); }}
p : a pipe input of program p1 program p2: output 2.2 How to Use Pipe Streams • A pipe is a channel for receiving data from one program (or thread) and sending the received data to the input of another. • PipedReader, PipedWriter ; PipedInputStream, PipedOutputStream • implement the input and output components of a pipe. • for p2, p is an PipedWriter ( or PipedOutputStream ) • for p1, p is a PipedReader ( or PipedInputstream )
pipe 1 pipe 2 Pipe example • a simple program to reverse, sort and reverse words in a file. • Note: without pipe, programmers would need 2 additional temporary files/buffers to store the intermediate results. sink (words) sink (rhymedWords)
The program import java.io.*; public class RhymingWords { public static void main(String[] args) throws IOException { FileReader words = new FileReader("words.txt"); // do the reversing and sorting Reader rhymedWords = reverse(sort(reverse(words))); // write new list to standard out BufferedReader in = new BufferedReader( rhymedWords ); String input; while ((input = in.readLine()) != null) System.out.println(input); in.close(); }
the reverse method public static Reader reverse(Reader source) throws IOException { BufferedReader in = new BufferedReader(source); PipedWriter pipeOut = new PipedWriter(); PipedReader pipeIn = new PipedReader( pipeOut ); // PipedReader pipeIn = new PipedReader( ); // alternative codes for // PipedWriter pipeOut = new PipedWriter( pipeIn ); // the above two lines PrintWriter out = new PrintWriter(pipeOut); // wrap pipeOut for easy write new ReverseThread(out, in).start(); return pipeIn; } pipeOut in(source) pipeIn reverse Thread out(pipeOut)
// source is a PipedReader public static Reader sort(Reader source) throws IOException { BufferedReader in = new BufferedReader(source); PipedWriter pipeOut = new PipedWriter(); PipedReader pipeIn = new PipedReader(pipeOut); PrintWriter out = new PrintWriter(pipeOut); new SortThread(out, in).start(); return pipeIn; } }
ReverseThread.java import java.io.*; public class ReverseThread extends Thread { private PrintWriter out; private BufferedReader in; public ReverseThread(PrintWriter out, BufferedReader in) { this.out = out; this.in = in; } public void run() { // entry point of a thread (invoked by start()), // like main() of a java program if (out != null && in != null) { try { String input; while ((input = in.readLine()) != null) { out.println(reverseIt(input)); out.flush(); } out.close(); } catch (IOException e) { System.err.println("ReverseThread run: " + e); } } } private String reverseIt(String source) { …} }
SortThread.java import java.io.*; public class SortThread extends Thread { private PrintWriter out = null; private BufferedReader in = null; public SortThread( PrintWriter out, BufferedReader in ) { this.out = out; this.in = in; } public void run() { int MAXWORDS = 50; if (out != null && in != null) { try { String[] listOfWords = new String[MAXWORDS]; int numwords = 0; // read words from in into listOfWords while ((listOfWords[numwords] = in.readLine()) != null) numwords++; quicksort(listOfWords, 0, numwords-1); // sort for (int i = 0; i < numwords; i++) out.println(listOfWords[i]); // output out.close(); } catch (IOException e) { System.err.println("SortThread run: " + e); } } }
quicksort private static void quicksort(String[] a, int lo0, int hi0) { int lo = lo0; int hi = hi0; if (lo >= hi) return; String mid = a[(lo + hi) / 2]; while (lo < hi) { while (lo<hi && a[lo].compareTo(mid) < 0) lo++; while (lo<hi && a[hi].compareTo(mid) > 0) hi--; if (lo < hi) { String T = a[lo]; a[lo] = a[hi]; a[hi] = T; lo++; hi--; } } if (hi < lo) { int T = hi; hi = lo; lo = T; } quicksort(a, lo0, lo); quicksort(a, lo == lo0 ? lo+1 : lo, hi0); }}
3. Using the processing streams Using Streams to Wrap Other Streams : • The reverse method contains some other interesting code; in particular, these two statements: BufferedReader in = new BufferedReader(source); ... PrintWriter out = new PrintWriter(pipeOut); general format: • WrappedClass w = new WrappedClass( rawObject ) • where rawObjwect is an obejct of type rawClass which does not provide the needed method, while Wrapped class is an extension of rawClass with intended methods provided. • In revserse() method: • source is a [file | pipe] Reader, which does not provide the readln() method. • pipeOut is a [piped] writer, which does not provide the convenient println() method.
raw Input Stream program raw Output Stream BufferedInputStream BufferedOutputStream buffer buffer 3.2 Summary of the processing streams • Buffered Streams • Buffer data while reading or writing, thereby reducing the number of accesses required on the original data source. • typically more efficient than similar nonbuffered streams; suggest always wrap a buffer stream around any stream such as a file stream whose read/write operations are costly. • BufferedReader f = new BufferedReader(new FileReader(“data.txt”)); • BufferedOutputStream b = new BufferedOutputStream ( • new FileOutputStream(“dataout”));
underlying Input Stream program underlying Output Stream FilterInputStream FilterOutputStream transformation + additional functionality Transformation + additional functionality Filter Streams • Filter streams • contains some other input stream as its basic source of data, possibly transforming the data along the way or providing additional functionality. • Abstract classes, same their parent streams (without new methods). • They define the interface for filter streams, which filter data as it's being read or written.
program OutputStream InputStream InputStreamReader OutputStreamWriter encoding encoding Byte2Char and char2Byte • A reader and writer pair that forms the bridge between byte streams and character streams. • default encoding from system property : “file.encoding” • Ex: • InputStreamReader reader = new InputStreamReader( • new FileInputStream(“data.txt”) , “Big5” ); • OutputStreamWriter writer = new OutputStreamWriter( • new FileOutputStream(“out.txt”));
SequenceInputStream • Concatenates multiple input streams into one input stream. • ex: SequenceInputStream sin = new SequenceInputStream(s1,s2); • ObjectInputStream and ObjectOutputStream • Used to serialize objects. • DataInputStream and DataOutputStream • Read / write primitive Java data types in a machine-independent format. • subclass of filter stream
LineNumberReader, LineNumberInputStream • Keeps track of line numbers while reading. • PushbackReader, PushbackInputStream • Two input streams each with a 1-character (or byte) pushback buffer. • Sometimes, when reading data from a stream, you will find it useful to peek at the next item in the stream in order to decide what to do next. However, if you do peek ahead, you'll need to put the item back so that it can be read again and processed normally. • PrintWriter, PrintStream • Contain convenient printing methods. • public void print(Type), and println([Type]), where the argument Type can be any type, either primitive or not. • These are the easiest streams to write to, so you will often see other writable streams wrapped in one of these.
How to Concatenate Files using the sequenceInputStream • a concatenation utility that sequentially concatenates files together in the order they are listed on the command line. • The main program import java.io.*; public class Concatenate { public static void main(String[] args) throws IOException { ListOfFiles mylist = new ListOfFiles(args); // mylist is an enumeration of objects of type InputStream SequenceInputStream s = new SequenceInputStream(mylist); int c; while ((c = s.read()) != -1) System.out.write(c); s.close(); } }
ListOfFiles.java import java.util.*; import java.io.*; public class ListOfFiles implements Enumeration { private String[] listOfFiles; private int current = 0; public ListOfFiles(String[] listOfFiles) { this.listOfFiles = listOfFiles; } public boolean hasMoreElements() { if (current < listOfFiles.length) return true; else return false; } public Object nextElement() { InputStreamin = null; if (!hasMoreElements()) throw new NoSuchElementException("NoMoreFiles."); String nextElement = listOfFiles[current]; current++; try { in= new FileInputStream(nextElement); } catch (FileNotFoundException e) { … }; } return in; } }
The SequenceInputerStream class • public class SequenceInputStream extends InputStream Constructor Summary • SequenceInputStream(Enumeration e) • e is an Enumeration of objects whose runtime type is InputStream. • SequenceInputStream(InputStream s1, InputStream s2) Method Summary : All overriding those from inputStream. • int available(), • void close(), • int read(), • int read(byte[] b [, int off, int len]) • …
Working with Filtered Streams • You attach a filtered stream to another stream to filter the data as it's read from or written to the original stream. • Subclasses of either FilterInputStream or FilterOutputStream: • DataInputStream and DataOutputStream : primitive data bytes • BufferedInputStream and BufferedOutputStream : • LineNumberInputStream : (deprecated) • PushbackInputStream : • PrintStream : • Subclasses of FilterReader and FilterWriter: • BushbackReader, LineNumberReader, … • Note: FilterReader/Writer use a character stream as its underlying stream while FilterInputStream/OutputStream use a byte stream as its underlying stream.
Writing Your Own Filtered Streams • Steps • Create a subclass of FilterInputStream and FilterOutputStream. • Override the read and write methods. • Override and/or define any other methods that you might need. • Make sure the input and output streams work together. • Example: • Use Adler32 to implement a CheckedInputStream and CheckedOutputStream to ensure that the data read match those written in other program [ now included in java.util.zip package] • Four classes and one interface make up this example program: • 1. CheckedOutputStream, CheckedInputStream. • 2. The Checksum interface and the Adler32 class compute a checksum for the streams. • 3. The CheckedIOTest class defines the main method for the program.
CheckedOutputStream import java.io.*; public class CheckedOutputStreamextends FilterOutputStream { private Checksum cksum; public CheckedOutputStream(OutputStream out, Checksum cksum) { super(out); this.cksum = cksum; } public void write(int b) throws IOException { out.write(b); cksum.update(b); } public void write(byte[] b) throws IOException { out.write(b, 0, b.length); cksum.update(b, 0, b.length); } public void write(byte[] b, int off, int len) throws IOException { out.write(b, off, len); cksum.update(b, off, len); } public Checksum getChecksum() { // additional functionality return cksum; }}