Engineering Full Stack Apps with Java and JavaScript
A stream can be considered as a sequence of bytes travelling from a source to a destination.
All input and output data transfer in Java happens through streams.
There can be different types of sources and destinations such as disk files, input devices like keyboards and even other programs, and there are different stream classes available corresponding to each of these types of sources and destinations.
All stream classes are present in the in the java.io package.
Based on the direction of data flow, streams can be categorized as input streams and output streams.
Based on the type of data we can classify streams as byte streams and text streams (aka character streams).
Byte streams
represent data in the form of bytes.
All byte stream classes are descended from InputStream and OutputStream.
Class names of byte streams end with the word stream as in FileInputStream and FileOutputStream.
Text streams (or character streams)
represent data as characters.
All character stream classes are descended from Reader and Writer.
Class names of text streams end with the word ‘Reader’ or ‘Writer’ as in FileReader and FileWriter.
Java stores character values using Unicode conventions. Text streams automatically convert the Unicode internal format to and from the local character set.
One stream may wrap around another stream to add some functionality to the inner stream or to make the inner stream do some low level tasks.
Filter streams wrap around other streams and transform the data providing additional functionality.
Subclasses of FilterInputStream are BufferedInputStream, CheckedInputStream, CipherInputStream, DataInputStream, DeflaterInputStream, DigestInputStream, InflaterInputStream, LineNumberInputStream, ProgressMonitorInputStream and PushbackInputStream.
Subclasses of FilterOutputStream are BufferedOutputStream, CheckedOutputStream, CipherOutputStream, DataOutputStream, DeflaterOutputStream, DigestOutputStream and InflaterOutputStream.
To improve efficiency we can use Buffered classes in connection with other streams
BufferedOutputStream can be used along with FileOutputStream to write data to a file. The characters will not be directly written to the file, but to the buffer. When the buffer is full, then the FileOutputStream will write the entire buffer in a single step into the file.
Similarly we can use BufferedInputStream to read a buffer full of data at a time from the file.
Another example is DataInputStream; we can attach the keyboard to a data input stream as:
DataInputStream dis=new DataInputStream(System.in);.
Stream variables in System class
java.lang.System class’s static member variable ‘in’ (System.in) is of type PrintStream and represents the standard input device that is keyboard by default.
System.out of type PrintStream and System.err of type InputStream, both are used to display messages on the default output device, which is monitor.
System.out is used to display normal messages whereas System.err is used to display error messages.
Text streams as wrappers for byte streams
Text streams often act as wrappers for byte streams; the byte streams perform the low level physical IO operations, and text streams handle the translation between characters and bytes.
Many readers cannot wrap around a byte stream. InputStreamReader can be useful in such cases as it can accept byte streams and act as a bridge between character streams and byte streams.
Example:
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.println(“Enter the filename”);
String fname=br.readLine();
This code will print "Enter the filename" to the console and then read a line from the console.
Markable streams provide the capability to mark a position in the stream and then later reset the stream so that it can be reread from the marked position.
The markSupported() method returns true if the stream is markable.
The mark() method marks a position in the stream and it takes the buffer capacity as an integer parameter.
The buffer memory is used to keep track of the data between the mark and the current position and when this buffer memory is exceeded, the mark becomes invalid.
The reset() method simply repositions the stream to its last marked position.