Você está na página 1de 19

Streams

- Java input and output is based on the use of streams.

- Streams are sequences of bytes that travel from a source to a destination


over a communication path. If your program is writing to a stream, it is the
stream's source. If it is reading from a stream, it is the stream's destination.

- The communication path is dependent on the type of I/O being performed. It


can consist of memory-to-memory transfers, file system, network, and other
forms of I/O.

- A Stream is an abstract representation of an input or output device that is a


source of or destination for data. The java.io package supports two types of
streams, Binary Streams, which contain binary data, and character streams,
which contain character data.

- When you write data to a stream as a series of bytes, that is binary data, it is
written to the stream exactly as it appears in memory. No transformation of
the data takes place. Numerical values are just written as a series of bytes.

- Character streams are used for storing and retrieving text. You can also use
character streams to read a text file not written by a java program.

- All numeric values are converted to a textual representation before written to


the stream. This involves formatting the data to generate a character
representation of the data value.

- All Unicode Characters are automatically converted to the local


representation of the characters as used by the host machine and then these
are written to the file.

- Unicode uses 16 bits to represent each character. If the high-order 9 bits are
all zeros, then the encoding is simply standard ASCII, otherwise the bits
represents a character that is not represented in 7-bit ASCII. Java’s char
datatype uses Unicode Encoding.

- Unicode’s 16-bit is sufficient to encode most alphabets but pictographic Asian


Languages like Japanese, Vietnamese present a problem. The answer for
this is UTF (UCS Transformation format and UCS stands for Universal
Character Set).

- UTF encoding uses as many bits as needed to encode a character: fewer


bits for smaller alphabets and more bits for larger Asian alphabets.
- A Character Encoding is a mapping between a character set and a range of
binary numbers. Every Java platform has a default character encoding, which
is used to interpret between internal Unicode and external bytes. The default
ASCII encoding is “8859_1”.

The important classes in the io.package are

a) File – An object of this class represents a pathname either to a file that


you will access for input or output or to a directory.
b) Output Stream – Base class for Byte Stream output.
c) Input Stream – Base Class for Byte Stream Input.
d) Writer – Base class for Character stream Output.
e) Reader – Base class for Character stream Input.
f) RandomAccessFile – Random Access to a File.

- Streams are powerful because they abstract away the details of the
communication path from input and output operations. This allows all I/O
to be performed using a common set of methods.

The File Class

- File class represents the name of a file or directory that might exist on the
hose machine’s file system.

- The constructors are

File (String file)


File(String dir, String subpath)
File(File dir, String subpath)

The methods are:

Boolean exists() – Where the file or directory exists or not

String getAbsolutePath() – This returns the absolute and not the relative path
of file or directory.

String getName()

String getParent() – This returns the name of the directory that contains the
File.

Boolean isDirectory()
Boolean isFile()

String [] list() – This returns an array containing the name of files and
directories within the File (which should be a directory).

Boolean canRead()

Boolean canWrite()

long length()

Boolean mkdir(File f)

boolean renameTo (File newname)

This Example is to show how to use the list () method.

import java.awt.*
import java.io.File

class Lister extends Frame


{
TextArea ta

public static void main (String arg[])


{
//get path or dir to be listed. default to c:\ if no command line argument

String path = “.”;


if(args.length >=1)
path = args[0];

// make sure the path exists and is a directory

File f = new File(path)


if (!f.isDirectory())

System.out.println(Does not exiss or not dir: - “ + path)

System.exit(0);
}

//Recursively list contents

Lister l = new Lister(f);


l.setVisible(true);
}

Lister(File f)
{
setSize(300,400);
ta = new TextArea();
ta.setFont(new Font(“Monospaced”, Font.PLAIN, 14));
add(BorderLayout.Center,ta);
recurse(f,0);
}

// recursively list the contents of a direfile, Indent _ 5 space for each level of
depth.

void recurse(File dirfile, int depth)


(
String contents[] = dirfile.list();

for (int I = 0; I<contents.length, I++)


{
// for each child..

for (int space = 0, space<depth; spaces++)

// Indent

ta.append(“ “);

ta.append (contents[I] + “\n”);


// Print name

File child = new File(dirfile, contents[I];

if (child.isDirectory())
recurse(child, depth+1)
// Recurse if dir
}
}
}

IMP: constructing or garbage collecting an instance of File has no effect on


the local file system.

FileDemo
FileSplitter1
FileLister
DirList

FilenameFilter Interface

- If we want to limit the number of files returned by the list () method to include
only those files that match a certain filename or filter, we have to implement
this interface.

- This interface has only one method accept () which is called once for each
file in the list.

boolean accept (File d, String name);

- The accept method will return true for files in the directory specified by d that
should be included in the list and returns false for files that should be
excluded.

- For using this method, we have to use the overloaded version of list () that is

String [] list (FilenameFilter fnf);

See TestFF

RandomAccessFile Class

- One way to ready or modify a file is to use the java.io.RamdomAccessFile


class. This class represents a model of files that is imcompatible with the
Stream / Writer classes.

- With a RamdomAccessFile, you can seek a desired position within a file and
then read or write a desired amount of data. The RamdomAccessFile
provides method that support seeking, reading and writing

Constructors

RamdomAccessFile(String file, String mode // which can be ‘r’ or ‘rw’)

The ‘rw” form of constructor is useful when you want to open some of the
methods of the File class before opening a RAF, so that a instance of File is
in hand when calling the RAF constructor.

Constructing a RAF is similar like constructing an instance of File.

After a random Access file is created, you can seek to any byte position within
the file and then read or write. Pre java systems have supported this seeing to a
position relative to the beginning of the file, end of the file or the current position
of the file. The methods

- long getFilePointer () throws IOException – This returns the current


position within the file, in bytes, Subsequent reading and writing will take
place starting at this position.

- long length() throws – length of file in bytes

- void seek( long position) thro – This sets the current position within the
file in bytes. Subsequent reading and writing will take place at this
position. Files start at position 0.

The common methods that support reading and writing are:

1. int read() - this returns the next byte from the file or –1 is end of file

2. int read(byte d[]) – attempts to read enough bytes t fill array d[]

3. int read(byte d[], int o, int n) – attempts to read n number of bytes into
array d[] starting at o.

RamdomAccessFile supports reading and writing of all primitive data


types.

When RAF is no longer needed, it should be closed:

void close() throws IOException

Pls see: RAFExample1

Streams:

a) Low Level InputStream reads bytes from an input device and returns bytes
to its callers.

b) High Level Filter Input Streams read bytes from a low level input stream or
from another filter input stream and returns general format data to its
caller.

c) Low Level OutputStream receives bytes and writes bytes to an output


Device.
d) High Level Filter Output Stream received general format data such as
primitives and writes bytes to a low level output stream or to another filter
output stream.

The important Methods in the abstract InputStream class is:

a) int read() – returns the integer representation of the next available byte
of input. –1 is the end of file is encountered.

b) int read (byte b[]) – this will read the bytes in the array.

c) int read(byte b[], int o, int no) – this will read no number of bytes
starting at 0.

d) int available() – returns the number of bytes of input currently available


for reading.

e) long skip(long no) – Ignores, the no number of bytes returning the


actual number of bytes ignored.

Low Level Streams

a) FileInputStream
b) ByteArrayInputStream
c) SequenceInputStream

FileInputStream

- This class will enable us to create a IS that you can use to read bytes
from a file.

- The common Constructors are as under:

FIS(String filename);
FIS(File f);

- Either of this will throw a checked exception and hence will have to be
put in a try / catch block or the main method will have to throw this
FileNotFoundException.

FileOutputStream

- FOS is used to create an OutputStream that u can use to write bytes to a


file.

- The most common used constructors are:


FOS(String s)
FOS(File f)
FOS(String s, boolean append)

- This class can throw IOException or SecurityException.

- IMP: Creating of a file is not dependent on whether the file is already


existing or not. This will create another file and incase there is a existing
file, the same will be overwritten.

ByteArrayInputStream

- This is an implementation of an InputStream that uses byte array as the


source.

- The two constructors for this are:

BAIS (byte b[])


BAIS (byte b[], int start, int noofbytes)

- BAIS implements both mark () and reset (). However if mark () has not
been called, then reset () sets the stream pointer to the start of the
stream.

ByteArrayOutputStream

- This is an implementation of an output stream that uses a byte array as


its destination.

- The two constructors are:

BAOS () // buffer size of 32 bytes is created.


BAOS(int noofbytes) // buffer as per the noofbytes specified

- To write normally use the write().


- To write to byte array use the method toByteArray().
- To write to a file use the method writeTo (OutputStream).

SequenceInputStream

- This class allows you to concatenate multiple InputStreams.

- The two constructors for this are:

SIS (IS one, IS two);


SIS (Enumeration s)

- In the case of the first constructor, the class reads requests from the first
IS until it runs out and then switches to the other and so on.

- In the case of Enumeration, it will continue through all the IS until the end
of the last one is reached.

HighLevelStreams

a) BufferedInputStream
b) DataInputStream
c) PushbackInputStream

- The High Level Streams take Low Level streams always as the
parameter in the constructors.

BufferedInputStream and BufferedOutputStream

- The buffered streams allow you to attach a memory buffer to the IO. This
buffer allows java to do IO operations on more than one byte at a time,
hence increasing performance.

- The BIS allows you to wrap any IS and achieve performance


improvement.

PushbackInputStream

- One of the uses of buffering is the implementation of pushback.

- Pushback is used on an InputStream to allow a byte to be read and then


returned (that is pushed back) to the stream.

- The two Constructors for this are:

PBIS (IS) // in this case only one byte is pushed


PBIS (IS,int n) // in this case n number of bytes are returned to the
IS

DataInputStream

- A data input stream lets an application read primitive Java data types
from an underlying input stream in a machine-independent way. An
application uses a data output stream to write data that can later be read
by a data input stream.
- The constructor for a DIS require InputStream as its parameter

DataInputStream( inputstream) // pass an instance of a input stream. The most


commonly used input methods of DIS are

readBoolean
readByte - and so on

Example

try{

FIS a = new FIS(“file name”)


DIS dis = new DIS(a)
double d = dis.readDoube()

dis.close()
fis.clost()

catch (Exception)

// We must close the streams in the order in which we opened them.

-
-

Readers & Writers

- While the Byte Stream provides all the functionality, they cannot work
directly with Unicode characters.

- use the readLine () of the BufferedReader

//The source code of the FileIOApp program

import java.lang.System;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.File;
import java.io.IOException;

public class FileIOApp {


public static void main(String args[]) throws IOException {
FileOutputStream outStream = new FileOutputStream("test.txt");
String s = "This is a test.";
for(int i=0;i<s.length();++i)
outStream.write(s.charAt(i));
outStream.close();
FileInputStream inStream = new FileInputStream("test.txt");
int inBytes = inStream.available();
System.out.println("inStream has "+inBytes+" available bytes");
byte inBuf[] = new byte[inBytes];
int bytesRead = inStream.read(inBuf,0,inBytes);
System.out.println(bytesRead+" bytes were read");
System.out.println("They are: "+new String(inBuf,0));
inStream.close();
File f = new File("test.txt");
f.delete();
}
}

//The source code of the PushbackIOApp program.

import java.lang.System;
import java.io.PushbackInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class PushbackIOApp {


public static void main(String args[]) throws IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
String s = "This is a test.";
for(int i=0;i<s.length();++i)
outStream.write(s.charAt(i));
System.out.println("outstream: "+outStream);
System.out.println("size: "+outStream.size());
ByteArrayInputStream inByteArray;
inByteArray = new ByteArrayInputStream(outStream.toByteArray());
PushbackInputStream inStream;
inStream = new PushbackInputStream(inByteArray);
char ch = (char) inStream.read();
System.out.println("First character of inStream is "+ch);
inStream.unread((int) 't');
int inBytes = inStream.available();
System.out.println("inStream has "+inBytes+" available bytes");
byte inBuf[] = new byte[inBytes];
for(int i=0;i<inBytes;++i) inBuf[i]=(byte) inStream.read();
System.out.println("They are: "+new String(inBuf,0));
}
}

//The source code of the LineNumIOApp program.

import java.lang.System;
import java.io.LineNumberInputStream;
import java.io.FileInputStream;
import java.io.DataInputStream;
import java.io.IOException;

public class LineNumIOApp {


public static void main(String args[]) throws IOException {
FileInputStream inFile = new FileInputStream("LineNumIOApp.java");
LineNumberInputStream inLines = new LineNumberInputStream(inFile);
DataInputStream inStream = new DataInputStream(inLines);
String inputLine;
while ((inputLine=inStream.readLine()) != null) {
System.out.println(inLines.getLineNumber()+". "+inputLine);
}
}
}

/*LineNumIOApp reads the LineNumIOApp.java source file and displays it using


line numbers. It uses three nested input stream objects. First it creates a
FileInputStream object and assigns it to the inFile variable. It then uses this
object to create a LineNumberInputStream object, which it assigns to inLines.
Finally, it creates a DataInputStream object using inLines and assigns it to
inStream.*/

//The source code of the DataIOApp program.

import java.lang.System;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.File;
import java.io.IOException;

public class DataIOApp {


public static void main(String args[]) throws IOException {
File file = new File("test.txt");
FileOutputStream outFile = new FileOutputStream(file);
DataOutputStream outStream = new DataOutputStream(outFile);
outStream.writeBoolean(true);
outStream.writeInt(123456);
outStream.writeChar('j');
outStream.writeDouble(1234.56);
System.out.println(outStream.size()+" bytes were written");
outStream.close();
outFile.close();
FileInputStream inFile = new FileInputStream(file);
DataInputStream inStream = new DataInputStream(inFile);
System.out.println(inStream.readBoolean());
System.out.println(inStream.readInt());
System.out.println(inStream.readChar());
System.out.println(inStream.readDouble());
inStream.close();
inFile.close();
file.delete();
}
}

/*The RandomIOApp program provides a simple demonstration of the capabilities


of
random-access I/O. It writes a boolean, int, char, and double value to a file and
then uses the seek() method to seek to offset location 1 within the file. This is
the position after the first byte in the file. It then reads the int, char, and
double values from the file and displays them to the console window. Next, it
moves
the file pointer to the beginning of the file and reads the boolean value that was
first written to the file. This value is also written to the console window.

The source code of the RandomIOApp program is shown.*/

import java.lang.System;
import java.io.RandomAccessFile;
import java.io.IOException;

public class RandomIOApp {


public static void main(String args[]) throws IOException {
RandomAccessFile file = new RandomAccessFile("test.txt","rw");
file.writeBoolean(true);
file.writeInt(123456);
file.writeChar('j');
file.writeDouble(1234.56);
file.seek(1);
System.out.println(file.readInt());
System.out.println(file.readChar());
System.out.println(file.readDouble());
file.seek(0);
System.out.println(file.readBoolean());
file.close();
}
}

/*Although the processing performed by RandomIOApp is quite simple, it


illustrates how
random I/O allows you to move the file pointer to various locations within a file to
directly access values and objects contained within the file. */

Object Persistence

Persistence is the ability of an object to record its state so that it can be


reproduced in the future, perhaps in another environment. For Example, a
persistent object might store its fate in a file. The file can be used to restore the
object in a different runtime environmentally. It is not the object itself that persists,
but rather the information necessary to construct a replica of the object. When an
object is serialised all of the object’s data but not its methods or class definition is
written to a stream.

Serialization

An object records itself by writing out the values that describe its state. This
process is know as serialisation because the object is represented by an ordered
series of bytes. Java provides classes that write objects to streams and restore
objects from streams.

The main task of serialization is to write out the values of an object’s instance
variables. If a variable is a reference to another object, the referenced object
must also be serialised. Serialization may involve serializing a complex tree
structure that consists of the original object, the object’s object and so on.

Not all classes are capable of being serialized. Only objects that implement the
Serializable or Externalizable interfaces may successfully be serialized. Both the
classes are in java.io package. A Serializable object can be serialized by another
object, which is in practice is a type of output stream. An Externalizable object
must be capable of writing its own state, rather than letting the work be done by
another object.
The Serializable Interface

This interface does not have any methods. When a class declares that it
implements Serializable, it is declaring that it participates in the serialization
protocol. When an object is Serializable and the object’s state is written to a
stream, the stream must contain enough information to restore the object. This
must hold true even if the class being restored has been updated to a more
recent (but compatible) version. One can serialize any class as long as the class
meets the following criteria:

a) The class or one of its super classes, must implement the


java.io.Serializable interface.
b) The class can implement the writeObject () to control data that is being
saved and append new data to existing saved data.
c) The class can implement the readObject () to read the data that was
written by the corresponding writeObject () method.

If a Serializable class has variables that should not be serialized those variables
must be marked with the transient keyword. The serialization process will ignore
any variables marked as transient. In general, references to AWT classes that
rely on System peers should be marked as transient. Many things - like static
data, open file handles, socket connections and threads will not be Serializable
since they represent items that are very JVM specific.

Externalizable Interface

The Externalizable interface identifies objects that can be saved to a stream but
are responsible for their own states. When an exter object is written to a stream,
the stream is responsible for storing the name of the object’s class, the object
must write its own data. An exter class must adhere to this interface by providing
a writeExternal () for storing its state during serialization and readExternal () for
restoring its state during deserialization.

Object Output Stream

Objects that can serialize other objects implement the ObjectOutput Interface
from the io package. This interface is implemented by output stream class and
extends the DataOutput class.

The essential of the interface is writeObject, which writes object to a stream.


Static and transient data are not written and all other data including private are
written.

The DataOutput interface support writing of primitive data types and these
methods are used for writing out an object’s primitive instance variables.
Serializable objects are represented as streams of bytes, rather than as
characters. Therefore they are handled by streams rather than by character
oriented streams.

When an object is to be serialised to a file, the first step is to create an output


stream that talks to the file

FileOutPutStream fos = new FileOutPutStream (“obj.file”)

The next step is to create an object output stream and chain it to the fos

ObjectOutput oo = new ObjectOutput (fos);

The object output stream automatically writes a header into the streams; the
header contains a magic number and a version. This data is written automatically
with the writeStreamHeader () when the object output stream is created.

After writing the header; the oos will write the bit representation of an object to
the oos using the writeObject method. Note: Without calling the reset () of the
java.io.Serializable you cannot use the same stream to write the same object
reference twice.

Deserialization

The obj i.s class reads serialized object data. By using the methods of this class,
a program can restore a serialised object along with the entire tree of objects
referred to by the primary object from the stream. Primitive data type may also be
read from an obj i.s.

The constructor calls the class’s readStreamHeader() method to verify the


header and the version that were written into the stream by the corresponding
object output stream. If a problem is detected with the header or the version a
StreamCorruptedException is thrown. The primary method of the O inputstream
class is readObject(), which deserializes an object from the data source stream.
The deserialized object is returned as an object; the caller is responsible for
casting it into the correct type.

The Known Objects Table

During deserialization, a list is maintained of objects that have been restored


from the stream. This list is called the known objects table.

If the data being written is of a primitive type, it is simply treated as a sequence of


bytes and restored from the input stream. If the data being restored is a string, it
is read using string UTF encoding the string will be added to the known objects
table.
If the object being restored is an array, the type and length of the array are
determined, Next memory for the array is allocated and each of the elements
contained in the array is read using the appropriate read method. Once the array
is reconstructed, it is added to the table. If it is an array of object (as opposed to
primitives) then each object is deserialised and added to the table.

Object Validation

Once an object has been retrieved from a stream, it must be validated so it can
become a full fledged object and can be used by a the program that deserialized
it. The validateObject() method is called when a complete graph of objects has
been retrieved from a stream. If the primary object cannot be made valid, the
validation will stop and an exception will be thrown.

Security for Serialized data

Serialization can involve storing an object’s data on a disk file or transmitting the
data across the network. In both cases, there is a potential security problem
because the data is located outside the JVM – beyond the reach of java’s
security mechanism.

The writeExternal () is public so any object can make an externalizable or


serializable object write itself into a stream. you should be careful when deciding
whether or not writeExternal () should serialize sensitive private data. When an
object is restored via an ordinary readExternal () call its sensitive values are
restored into private variables and no harm is done. However while the serialised
data is outside the system, an attacker could access the data decode its format
and obtain the sensitive values. When a object is being serialised, all the
reachable objects of its ownership graph are potentially exposed. The best
protection for an object that has fields that should not be stored is to label those
fields with the transient keyword.

Serialization Exceptions: 6 Exceptions.

1) Invalid ClassException: Typically thrown when the class type cannot be


determined by the reserialization stream or when the class that is
being returned cannot be represented on the system retrieving the
object. This is also thrown if the deserialized class is not declared
public or if it does not have a public default constructor.

2) NotSerializableException: Typicall thrown by externalizable objects


(which are not responsibl for their own reserialization) on detection of a
corrupted input stream. The corruption is generally indicated by an
unexpected invariant value or simply when u try to serialize a
nonserialisable object.
3) StreamCorruptedException: When the stored object’s header or control
data is invalid.

4) OptionalDataException: Thrown when a stream is supposed to contain


a object, but it actually contains only primitive data.

5) ClassNotFoundException: Thrown when the class of the deserialized


object cannot be found on the read side of the stream

6) IOException: Thrown when there is an error related to the stream that


the object is being written to or read from.

It is important to note that most stream methods can throw an IOException,


therefore any time you access a stream you should enclose the code within
a try and catch block.

The following example reads a string from the keyboard and prints it

import java.io.*;
class Input
{
public static void main (String arg[]) throws IOException
{
System.out,print (“Enter a String “);
BufferedReader br =new BufferedReader ( new InputStreamReader
(System.in)));
System.out.println (“The String you have entered is: “+br.readLine));
}
}

By using streams, you can create java programs that read data form a
source, process the data and write the results to a destination.

import java.io.*;

class CopyFile
{
public static void main (String arg[])
{
InputStream m_input = null;
OutputStream m_output = null;

try
{
System.out.println(“Opening Files..”)’

m_input = new FileInputStream (“CopyFile.java”);


m_output = new FileOutputStream (“Copyof_CopyFile.txt”);

System.out.println (“Copying data...”);

byte data;

while ((data=(byte)m_input.read()) != -1)


{
m_output.write(data);

System.out.println(“File copied”);
}

catch (Exception e)
{
System.out.println(“IO Error” + e.getMessage ());
}

System.exit (0);
}
}

Você também pode gostar