Transcript lecture

Java I/O
L. Grewe
Overview of java.io




methods for accessing file, text data,
object serialization and
internationalization
Sequential and Random access
Reading and writing of primitive
values
Applications and applets are provided
with three streams automatically



System.out (output stream)
System.in (input stream)
System.err (error stream
Uses Streams

Two kinds of basic streams:
1.
byte based streams


2.
8 bits, data-based
input streams and output streams
character based streams


16 bits, text-based
readers and writers
Byte Streams


Two parent abstract classes: InputStream and
OutputStream
Reading bytes:
• InputStream class defines an abstract method
public abstract int read() throws IOException


Designer of a concrete input stream class overrides this method to
provide useful functionality.
E.g. in the FileInputStream class, the method reads one byte
from a file
• InputStream class also contains nonabstract methods to read
an array of bytes or skip a number of bytes

Writing bytes:
• OutputStream class defines an abstract method
public abstract void write(int b) throws IOException
• OutputStream class also contains nonabstract methods for
tasks such as writing bytes from a specified byte array

Close the stream after reading of writing to it to free up
limited operating system resources by using close()
Byte Streams (Binary
Streams)…some of the hierarchy
FileInputStream
InputStream
BufferedInputStream
FilterInputStream
DataInputStream
Object
FileOutputStream
BufferedOutputStream
OutputStream
FilterOutputStream
DataOutputStream
PrintStream
Byte Stream some of the
hierarchy
AutioInputStream
FileInputStream
InputStream
ObjectInputStream
SequenceInputStream
ByteArrayInputStream
PipedInputStream
FilterInputStream
Byte Streams
FileOutputStream
ObjectOutputStream
OutputStream
ByteArrayOutputStream
PipeOutputStream
FilterOutputStream
Java Programming
Byte Streams
import java.io.*;
The abstract class InputStream
declares methods to read bytes from a
particular source.
public class CountBytes {
public static void main(String[] args) Type is InputStream
throws IOException
{
InputStream in;
Reads a single byte of data and returns
if (args.length == 0)
the byte that was read, as an integer in
the range 0 to 255, not -128 to
in = System.in;
127(unsigned).
else
in = new FileInputStream(args[0]);
}
}
int total = 0;
while (in.read() != -1)
total++;
System.out.println(total + " bytes");
Example code1:
import java.io.*;
class CountBytes {
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream(args[0]);
int total = 0;
while (in.read() != -1)
total++;
in.close();
System.out.println(total + ” bytes”);
}
}
Example code2:
import java.io.*;
class TranslateByte {
public static void main(String[] args) throws IOException {
byte from = (byte)args[0].charAt(0);
byte to = (byte)args[1].charAt(0);
int x;
while((x = System.in.read()) != -1)
System.out.write(x == from ? to : x);
}
}
If you run “java TranslateByte b B” and enter text bigboy via the
keyboard the output will be: BigBoy!
Byte Stream - output
Byte Stream - Output
import java.io.*;
The abstract class OutputStream
provides an abstraction for writing bytes
to a destination.
public class TranslateByte {
public static void main(String[] args)
throws IOException
{
byte from = (byte) args[0].charAt(0);
byte to = (byte) args[1].charAt(0);
int b;
while ((b = System.in.read()) != -1)
System.out.write(b == from ? to : b);
}
Run:
}
Type is PrintStream
Java TranslateByte b B
Result: (input  abracadabra!)
aBracadaBra!
Character streams


Two parent abstract classes for characters: Reader and
Writer. Each support similar methods to those of its byte
stream counterpart–InputStream and OutputStream,
respectively
The standard streams—System.in, System.out and
System.err—existed before the invention of character
streams. So they are byte streams though logically they
should be character streams.
Character Streams - Reading
BufferedReader
InputStreamReader
Reader
StringReader
CharArrayReader
PipedReader
FilterReader
Character Streams - Writing
BufferedWriter
OutputStreamWriter
Writer
StringWriter
CharArrayWriter
PipedWriter
FilterWriter
PrintWriter
Conversion between byte and character streams

The conversion streams InputStreamReader and
OutputStreamReader translate between Character and byte
streams
•
•
•
•



public InputStreamReader(InputStream in)
public InputStreamReader(InputStream in, String encoding)
public OutputStreamWriter(OutputStream out)
public OutputStreamWriter(OutputStream out, String
encoding)
read method of InputStreamReader read bytes from their
associated InputStream and convert them to characters
using the appropriate encoding for that stream
write method of OutputStreamWriter take the supplied
characters, convert them to bytes using the appropriate
encoding and write them to its associated OutputStream
Closing the conversion stream also closes the associated
byte stream – may not always desirable
Character Stream Example
import java.io.*;
The abstract classes for reading and
writing streams of characters are Reader
and Writer.
public class CountSpace {
The abstract class Reader provides a
public static void main(String[] args)
character stream analogous to the byte
throws IOException
stream InputStream and the methods of
{
Reader essentially mirror those of
Reader in;
InputStream.
if (args.length == 0)
in = new InputStreamReader(System.in);
else
Run:
in = new FileReader(args[0]);
Java CountSpace CountSpace.java
Result:
}
}
int ch;
520 characters 172 spaces
int total;
int spaces = 0;
for (total = 0; (ch = in.read()) != -1; total++) {
if (Character.isWhitespace((char) ch))
spaces++;
}
The conversion streams
System.out.println(total + " chars "
InputStreamReader and
+ spaces + " spaces");
OutputStreamWriter translate between
character and byte streams using either a
specified character set encoding or the
default encoding for the local system.
Reading from a Stream


The basic read() method reads a byte at a time.
Some other methods that read more than 1 byte
• public int read(byte[] data) throws IOException

Tries to read enough bytes to fill the array data
• public int read(byte[] data, int offset, int length) throws
IOException

Tries to read length bytes from stream and store in data[] at starting index
offset
• These methods then return the number of bytes actually read. You
should not assume that the array will be filled or that length bytes will
actually have been read. If the end of stream is encountered, -1 is
returned
Reading

Use other classes with richer
methods (i.e. DataInputStream) to
read in different data types
Writing





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. voidwrite(String str)
Write a string. voidwrite(String str, int off, int len)
Write a portion of a string.
Other methods – for byte based – print*(*)
abstract void close()
Close the stream, flushing it
abstract void flush()
Flush the stream. voidwrite(char[] cbuf)
Write an array of characters.
File I/O :

The File class
The File class is particularly useful for retrieving information
about a file or a directory from a disk.
• A File object actually represents a path, not necessarily an
underlying file
• A File object doesn’t open files or provide any file-processing
capabilities

Three constructors
•
•
•

public File( String name)
public File( String pathToName, String name)
public File( File directory, String name)
Main methods
• boolean canRead() / boolean canWrite()
• boolean exists()
• boolean isFile() / boolean isDirectory() / boolean
isAbsolute()
• String getAbsolutePath() / String getPath()
• String getParent()
• String getName()
• long length()
• long lastModified()
File I/O

Sequential-Access file: the File streams—
FileInputStream, FileOutputStream, FileReader and
FileWriter—allow you to treat a file as a stream to input
or output sequentially
• Each file stream type has three types of constructors




A constructor that takes a String which is the name of the file
A constructor that take a File object which refers to the file
A constructor that takes a FileDescriptor object
Random-Access file: RandomAccessFile allow you to
read/write data beginning at the a specified location
• a file pointer is used to guide the starting position
• It’s not a subclass of InputStream, OutputStream, Reader or
Writer because it supports both input and output with both
bytes and characters
Example of RandomAccessFile
import java.io.*;
class Filecopy {
public static void main(String args[]) {
RandomAccessFile fh1 = null;
RandomAccessFile fh2 = null;
long filesize = -1;
byte[] buffer1;
try {
fh1 = new RandomAccessFile(args[0], “r”);
fh2 = new RandomAccessFile(args[1], “rw”);
} catch (FileNotFoundException e) {
System.out.println(“File not found”);
System.exit(100);
}
try {
filesize = fh1.length();
int bufsize = (int)filesize/2;
buffer1 = new byte[bufsize];
fh1.readFully(buffer1, 0, bufsize);
fh2.write(buffer1, 0, bufsize);
} catch (IOException e) {
System.out.println("IO error occurred!");
System.exit(200);
}
}
}
Add more efficiency

BufferedReader reads text from a character-input stream,
buffering characters so as to provide for the efficient
reading of characters, arrays, and lines.
BufferedReader (Reader in)

For example:
 to wrap an InputStreamReader inside a
BufferedReader
BufferedReader in
= new BufferedReader(new
InputStreamReader(System.in));
 to wrap a FileReader inside a BufferedReader
BufferedReader in
= new BufferedReader(new FileReader(“fileName”));
then you can invoke in.readLine() to read from the
file line by line
import java.io.*;
public class EfficientReader {
public static void main (String[] args) {
try {
BufferedReader br = new BufferedReader(new FileReader(args[0]));
// get line
String line = br.readLine();
}
}
// while not end of file… keep reading and displaying lines
while (line != null) {
System.out.println("Read a line:");
System.out.println(line);
line = br.readLine();
}
// close stream
br.close();
} catch(FileNotFoundException fe) {
System.out.println("File not found: “+ args[0]");
} catch(IOException ioe) {
System.out.println("Can’t read from file: “+args[0]);
}
Buffering




Improves performance of I/O
Copies each output to a region of memory called a buffer
Entire buffer output to disk at once
One long disk access takes less time than many smaller ones
•
•
BufferedInputStream buffers file output
BufferedOutputStream buffers file input
Appending to a File

To append to file instead of overwriting it pass the boolean
value true as the second argument to the FileOutputStream()
constructor. For example,
FileOutputStream fos = new FileOutputStream(“File.txt", true);
More on Writing to a File

The java.io.FileWriter class writes text files using the
platform's default character encoding and the buffer size. If
you need to change these values, construct an
OutputStreamReader on a FileOutputStream instead.
LineNumberReader class

The java.io.LineNumberReader class is a subclass
of java.io.BufferedReader that keeps track of
which line you're currently reading. It has all the
methods of BufferedReader including readLine().
It also has two constructors, getLineNumber(),
and setLineNumber() methods:
•
•
•
•
public
public
public
public
LineNumberReader(Reader in)
LineNumberReader(Reader in, int size)
int getLineNumber()
void setLineNumber(int lineNumber)
The setLineNumber() method does not change the file pointer. It just changes
the value getLineNumber() returns.
For example, it would allow you to start counting from -5 if you knew there were
six lines of header data you didn't want to count.
Lets look at some examples

First ---- using DataInputStream and
DataOutputStream
Data Input/Output Stream example
OUTPUT
256 3.141592653589793 Jav
import java.io.*;
class DOSDISDemo
{
public static void main (String [] args)
{
DataOutputStream dos = null;
DataInputStream dis = null;
try
{
FileInputStream fis = new FileInputStream ("data.dat");
dis = new DataInputStream (fis);
try
{
FileOutputStream fos = new FileOutputStream
("data.dat");
dos = new DataOutputStream (fos);
System.out.println (dis.readInt ());
System.out.println (dis.readDouble ());
System.out.println (dis.readUTF ());
}
catch (IOException e)
{
System.out.println (e.getMessage ());
return;
}
finally
{
if (dis != null)
try
{ dis.close ();
}
catch (IOException e) { }
}
dos.writeInt (256);
dos.writeDouble (Math.PI);
dos.writeUTF ("Java");
}
catch (IOException e)
{ System.out.println (e.getMessage ());
return; }
finally
{ if (dos != null)
try
{ dos.close (); }
catch (IOException e) { }
}
}
}
Another Example--- Piped
Streams
A Motivation?
•Threads are often required to communicate.
•Can use piped streams.
•IDEA= connect a piped output stream to a piped input
stream.
•Then, one thread writes data to the piped output stream and
another thread reads that data by way of the piped input
stream.
•CAUTION= streams have limited sizes. As a result, a writing
thread could write more output to a piped output stream than
that stream can accommodate, and the excess output would
be lost. To prevent that from happening, the reading thread
must be responsive.
Buffered Streams, Piped Streams (here with
same thread)
Character
Stream
import java.io.*;
public class BufferedReaderTest {
public static void main(String[] args)
throws IOException
{
InputStream
BufferedReader charStream =
new BufferedReader (new
InputStreamReader(System.in));
String data = charStream.readLine(); //
Read a line from standard input
}
}
System.out.println("Input = " + data);
The Buffered stream classes buffer their data
to avoid every read or write going directly to
the next stream. These classes are often used
in conjunction with File streams.
import java.io.*;
class TextGenerator extends Thread {
private Writer out;
public TextGenerator(Writer out) {
this.out = out;
}
public void run() {
try {
try {
for (char c = 'a'; c <= 'z'; c++)
out.write(c);
} finally {
out.close();
}
} catch(IOException e) {
}
getUncaughtExceptionHandler().uncaughtExcepti
on(this, e);
}
}
public class Pipe {
public static void main(String[] args)
throws IOException
{
PipedWriter out = new PipedWriter();
PipedReader in = new PipedReader(out);
TextGenerator data = new TextGenerator(out);
data.start();
int ch;
while ((ch=in.read()) != -1)
System.out.print((char) ch);
System.out.println();
}
Result:
}
abcdefghijklmnopqrstuvwxyz
Another Example--LineNumberReader

Tracks Line numbers as you are
reading
Print Streams, LineNumberReader



The Print streams provide
methods that make it easy to
write the values of primitive types
and object to a stream, in a
human-readable text format
• print and println method
The call out.print(f) is equivalent
to
out.write(String.valueOf(f).getByt
es());
import java.io.*;
public class FindChar {
public static void main(String[] args)
throws IOException
{
if (args.length != 2)
throw new IllegalArgumentException(
"need char and file");
LineNumberReader
The LineNumberReader stream
keeps track of line numbers while
reading text.
Run:
%java FindChar I FindChar.java
Result:
‘I’ at line 4
}
}
int match = args[0].charAt(0);
FileReader fileIn = new
FileReader(args[1]);
LineNumberReader in = new
LineNumberReader(fileIn);
int ch;
while ((ch = in.read()) != -1) {
if (ch == match) {
System.out.println("'" + (char) ch +
"' at line " + in.getLineNumber());
return ;
}
}
System.out.println((char) match + " not
found");
Another Example …Pushback
Streams


Pushback is used on an input stream
to allow a byte to be read and then
returned(that is "pushed back") to
the stream.
PushbackInputStream provides a
mechanism to "peek " at what is
coming from an input stream without
disrupting it.
Pushback Streams



A Pushback stream lets you
push back, or “unread”
characters or bytes when
you have read too far.
Pushback is typically useful
for breaking input into
tokens.
For example, lexical
scanners often know that a
token (such as an identifier)
has ended only when they
have read the first character
that follows it.
The following example uses
PushbackInputStream to
report the longest
consecutive sequence of any
single byte in its input:
Run and Result:
% java SequenceCount
12345111
^D in Unix(or ^Z in Windows)
3 bytes of 49
import java.io.*;
public class SequenceCount {
public static void main(String[] args)
throws IOException
{
PushbackInputStream
in = new PushbackInputStream(System.in);
int max = 0; // longest sequence found
int maxB = -1; // the byte in that sequence
int b;
// current byte in input
}
}
do {
int cnt;
int b1 = in.read();
for (cnt = 1; (b = in.read()) == b1; cnt++)
continue;
if (cnt > max) {
max = cnt; // remember length
maxB = b1; // remember which byte value
}
in.unread(b); // pushback start of ntext seq
} while (b != -1); // until we hit end of input
System.out.println(max + " byte of " + maxB);
Another Example


Java I/O even has ability to read zip
files
java.util.zip
• ZipInputStream ,ZipOutputStream
Zip File Example –will list contents
// ZipReader.java
import java.io.*;
import java.util.zip.*;
class ZipReader
{
public static void main (String [] args)
{
if (args.length != 1)
{
System.out.println ("usage: java ZipReader pathname");
return;
}
ZipInputStream zis = null;
try
{
FileInputStream fis = new FileInputStream (args [0]);
zis = new ZipInputStream (fis);
ZipEntry ze;
while ((ze = zis.getNextEntry ()) != null)
System.out.println (ze.getName ());
}
// ZipReader.java
catch (IOException e)
{
System.out.println (e.getMessage ());
}
finally
{
try
{
zis.close ();
}
catch (IOException e)
{
}
}
}
}

To run ZipReader,
you need access to
either a Zip file or a
Jar file (which is
basically a Zip file
with a .jar extension
A useful class in I/O –the
StreamTokenizer


The StreamTokenizer gives simple
tokenization.
More general facility for scanning and
converting input text is provided by
the java.util.Scanner class.
StreamTokenzier

Four token type
• TT_WORD
• TT_NUMBER
• TT_EOL
• TT_EOF
Result
Input
(tokens.txt)
The price is $23.45.
Is that too expensive?
(I don’t think so.)
Run:
java
StreamTokenizerDemo
tokens.txt
1)
1)
1)
1)
1)
1)
2)
2)
2)
2)
2)
3)
3)
3)
3)
3)
3)
3)
The
price
is
$
23.45
.
Is
that
too
expensive
?
(
I
don’t
think
so
.
)
import java.io.*;
class StreamTokenizerDemo {
public static void main(String args[]) {
try {
FileReader fr = new FileReader(args[0]);
BufferedReader br = new BufferedReader(fr);
StreamTokenizer st = new StreamTokenizer(br);
st.ordinaryChar('.');
st.wordChars('\'', '\'');
while(st.nextToken() !=
StreamTokenizer.TT_EOF) {
switch(st.ttype) {
case StreamTokenizer.TT_WORD:
System.out.println(st.lineno() + ") " +
st.sval);
break;
case StreamTokenizer.TT_NUMBER:
System.out.println(st.lineno() + ") " +
st.nval);
break;
default:
System.out.println(st.lineno() + ") " +
(char)st.ttype);
}
}
fr.close();
}
catch (Exception e) {
System.out.println("Exception: " + e);
}
}
}
Another on ….Data Byte Streams



DataInput and DataOutput
These interfaces define
methods that transmit
primitive types across a
stream.
Read / Write methods
Read
readBoolean
readChar
readByte
readShort
readInt
readLong
readFloat
readDouble
readUTF
Write
Type
writeBoolean boolean
writeChar
char
writeByte
byte
writeShort
short
writeInt
int
writeLong
long
writeFloat
float
writeDouble double
writeUTF
String(in UTF format)
public static void writeData(double[] data,
String file)
throws IOException
{
OutputStream fout = new
FileOutputStream(file);
DataOutputStream out = new
DataOutputStream(fout);
out.writeInt(data.length)
for(double d : data) out.writeDouble(d);
out.close();
}
public static double[] readData(String file)
throws IOException
{
InputStream fin = new
FileInputStream(file);
DataInputStream in = new
DataInputStream(fin);
double[] data = new double[in.readInt()];
for (int i = 0; i < data.length; i++)
data[i] = in.readDouble();
in.close();
return data;
}
Reading and Writing Objects?

What if we could save and store and
object and read it (bring it back to
life)….wow!
Object Serialization

What is Object Serialization?
• Serialization: process of converting an object’s
representation into a stream of bytes
• Deserialization: reconstituting an object from a byte stream
• Process of reading and writing objects
• Writing an object is to represent its state in a serialized
form sufficient to reconstruct the object as it is read.
• serialization is the process of converting a object state
into a format that can be stored (for example, in a file or
memory buffer, or transmitted across a network connection
link) and "resurrected" later in the same or another
computer environment.
Serializing Objects

How to Write to an
ObjectOutputStream
• Writing objects to a stream
is a straight-forward
process. Example of
constructing a Date object
and then serializing that
object:
FileOutputStream out = new
FileOutputStream("theTime");
ObjectOutputStream s = new
ObjectOutputStream(out);
s.writeObject("Today");
s.writeObject(new Date());
s.flush();

How to Read from an
ObjectOutputStream
• Example that reads in the
String and the Date object
that was written to the file
named theTime in the read
example:
FileInputStream in = new
FileInputStream("theTime");
ObjectInputStream s = new
ObjectInputStream(in);
String today =
(String)s.readObject();
Date date =
(Date)s.readObject();
Serializing Objects

Providing Object Serialization for Your Classes
•
•
•
•
Implementing the Serializable Interface
Customizing Serialization
Implementing the Externalizable Interface
Protecting Sensitive Information
Files ---and Channels+
Accessing Files

Channels
• Channels were introduced in the 1.4 release of Java to provide a faster
capability for a faster capability for input and output operations with
files, network sockets, and piped I/O operations between programs
than the methods provided by the stream classes.
• The channel mechanism can take advantage of buffering and other
capabilities of the underlying operating system and therefore is
considerably more efficient than using the operations provided directly
within the file stream classes.

A summary of the essential role of each of them in file operations
• A File object encapsulates a path to a file or a directory, and such an
object encapsulating a file path can be used to construct a file stream
object.
• A FileInputStream object encapsulates a file that can be read by a
channel. A FileoutputStream object encapsulates a file that can be
written by a channel.
• A buffer just holds data in memory. The loaded data to be written to a
file will be saved at buffer using the buffer’s put() method, and
retrieved using buffer’s get() methods.
• A FileChannel object can be obtained from a file stream object or a
RandomAccessFile object.
Accessing Files
The hierarchy of the channel interfaces
Accessing Files
The Capacities of Different Buffers
Channel Example (ReadPrimes)
import
import
import
import
import
import
java.io.File;
java.io.FileInputStream;
java.io.IOException;
java.io.FileNotFoundException;
java.nio.ByteBuffer;
java.nio.channels.FileChannel;
try {
while(inChannel.read(buf) != -1) {
((ByteBuffer)(buf.flip())).asLongBuffer().g
et(primes);
// List the primes read on the same line
System.out.println();
for(long prime : primes)
System.out.printf("%10d", prime);
public class ReadPrimes {
public static void main(String[] args) {
File aFile = new File("primes.bin"); From the
FileInputStream inFile = null;
channel, read
buf.clear();
// Clear the
try {
data and save buffer for the next read
inFile = new FileInputStream(aFile);to the buffer
}
System.out.println("\nEOF reached.");
} catch(FileNotFoundException e) {
inFile.close();
// Close the file
e.printStackTrace(System.err);
and the channel
System.exit(1);
Channel Setup
}
} catch(IOException e) {
e.printStackTrace(System.err);
FileChannel inChannel =
System.exit(1);
inFile.getChannel();
}
final int PRIMECOUNT = 6;
System.exit(0);
ByteBuffer buf =
}
ByteBuffer.allocate(8*PRIMECOUNT);
} You also need to read the
long[] primes = new long[PRIMECOUNT];
“PrimesToFile.java” which prints prime
numbers to the file.
Buffer Setup