Chitika

Java I/O

I/O is a huge topic in general, and the Java APIs that deal with I/O in one fashion or another are correspondingly huge. A general discussion of I/O could include topics such as file I/O, console I/O, thread I/O, high-performance I/O, byte-oriented I/O, character-oriented I/O, I/O filtering and wrapping, serialization, and more.
Here's a summary of the I/O classes you'll need to understand:

File  
The API says that the class File is "An abstract representation of file and directory pathnames." The File class isn't used to actually read or write data; it's used to work at a higher level, making new empty files, searching for files, deleting files, making directories, and working with paths.

FileReader 
 This class is used to read character files. Its read() methods are fairly low-level, allowing you to read single characters, the whole stream of characters, or a fixed number of characters. FileReaders are usually wrapped by higher-level objects such as BufferedReaders, which improve performance and provide more convenient ways to work with the data.

BufferedReader
This class is used to make lower-level Reader classes like FileReader more efficient and easier to use. Compared to FileReaders, BufferedReaders read relatively large chunks of data from a file at once, and keep this data in a buffer. When you ask for the next character or line of data, it is retrieved from the buffer, which minimizes the number of times that time-intensive, file read operations are performed. In addition, BufferedReader provides more convenient methods such as readLine(), that allow you to get the next line of characters from a file.

FileWriter 
This class is used to write to character files. Its write()methods allow you to write character(s) or Strings to a file. FileWriters are usually wrapped by higher-level Writer objects such as BufferedWriters or PrintWriters, which provide better performance and higher-level, more flexible methods to write data.

BufferedWriter 
 This class is used to make lower-level classes like FileWriters more efficient and easier to use. Compared to FileWriters, BufferedWriters write relatively large chunks of data to a file at once, minimizing the number of times that slow, file writing operations are performed. In addition, the BufferedWriter class provides a newLine()method that makes it easy to create platform-specific line separators automatically.

PrintWriter  
This class has been enhanced significantly in Java 5. Because of newly created methods and constructors (like building a PrintWriter with a File or a String), you might find that you can use PrintWriter in places where you previously needed a Writer to be wrapped with a FileWriter and/or a BufferedWriter. New methods like format(), printf(), and append()make PrintWriters very flexible and powerful.

Using FileWriter and FileReader

In practice, you probably won't use the FileWriter and FileReader classes without wrapping them. That said, let's go ahead and do a little "naked" file I/O:


import java.io.*;
class Writer2 {
public static void main(String [] args) {
char[] in = new char[50]; // to store input
int size = 0;
try {
File file = new File("myjavacamp.txt"); // just an object
FileWriter fw = new FileWriter(file); // create an actual file
// & a FileWriter obj
fw.write("Welcome to My Java Camp\n"); // write characters to the file
fw.flush(); // flush before closing
fw.close(); // close file when done

FileReader fr = new FileReader(file); // create a FileReader object
size = fr.read(in); // read the whole file!
System.out.print(size + " "); // how many bytes read
      
for(char c : in) // print the array
System.out.print(c);
fr.close(); // again, always close
} catch(IOException e) { }
}
}
which produces the output:
                           Welcome to My Java Camp
Here's what just happened:
1. FileWriter fw = new FileWriter(file) did three things:
a. It created a FileWriter reference variable, fw.
b. It created a FileWriter object, and assigned it to fw.
c. It created an actual empty file out on the disk (and you can prove it).

2. We wrote 12 characters to the file with the write() method, and we did a flush() and a     close().
3. We made a new FileReader object, which also opened the file on disk for reading.
4. The read() method read the whole file, a character at a time, and put it into the char[] in.
5. We printed out the number of characters we read size, and we looped through the in array printing out each character we read, then we closed the file. Before we go any further let's talk about flush() and close(). When you write data out to a stream, some amount of buffering will occur, and you never know for sure exactly when the last of the data will actually be sent. You might perform many

write operations on a stream before closing it, and invoking the flush() method guarantees that the last of the data you thought you had already written actually gets out to the file. Whenever you're done using a file, either reading it or writing to it, you should invoke the close() method. When you are doing file I/O you're using expensive and limited operating system resources, and so when you're done, invoking close() will free up those resources. Now, back to our last example. This program certainly works, but it's painful in a couple of different ways:

1. When we were writing data to the file, we manually inserted line separators (in this case \n), into our data.
2. When we were reading data back in, we put it into a character array. It being an array and all, we had to declare its size beforehand, so we'd have been in trouble if we hadn't made it big enough! We could have read the data in one character at a time, looking for the end of file after each read(), but that's pretty painful too. Because of these limitations, we'll typically want to use higher-level I/O classes like BufferedWriter or BufferedReader in combination with FileWriter or FileReader.


Combining I/O classes

Java's entire I/O system was designed around the idea of using several classes in combination. Combining I/O classes is sometimes called wrapping and sometimes called chaining. The java.io package contains about 50 classes, 10 interfaces, and 15 exceptions. Each class in the package has a very specific purpose (creating high cohesion), and the classes are designed to be combined with each other in countless ways, to handle a wide variety of situations. When it's time to do some I/O in real life, refer the  java.io API, try to figure out which classes you'll need, and how to hook them together.
Now let's say that we want to find a less painful way to write data to a file and read the file's contents back into memory. Starting with the task of writing data to a file, here's a process for determining what classes we'll need, and how we'll hook them together:

                Table: java.io mini API
Java.io Class
Extends from
Key methods
File
Object
createNewFile(), delete(), exists(), isDirectory(), isFile(), list(), mkdir(), renameTo()
FileWriter
Writer
Close(), flush(), write()
BufferedWriter
Writer
Close(), flush(), newLine(), write()
PrintWriter
Writer
Close(), flush(), format(), printf(), print(), println(), write()
FileReader
Reader
Read()
BufferedReader
Readeer
Read(), readLine()


         Data streams can connect an application to:
        Disk files
        Sockets
        The console (keyboard / screen)
         A stream is a sequence of bytes 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
         A program can manage multiple streams simultaneously

         An input stream may be associated with the keyboard
         An input stream or an output stream may be associated with a file or network resource
         Different streams have different characteristics:
        A file has a definite length, and therefore an end
        Keyboard input has no specific end

Reading and Writing

         Reading
        open a stream
        while more information
        read information
        close the stream

         Writing
        open a stream
        while more information
        write information
        close the stream


Character & Byte I/O

         The java.io package contains many classes that allow us to define various streams with particular characteristics
         Some classes assume that the data consists of characters
         Others assume that the data consists of raw bytes of binary information

Character Streams

         Reader and Writer are the abstract superclasses for character streams in java.io.
         Reader provides the API and partial implementation for readers, streams that read 16-bit characters.
         Writer provides the API and partial implementation for writers, streams that write 16-bit characters.

Byte Streams
         InputStream and OutputStream are the abstract superclasses for byte streams in java.io.
         InputStream provides the API and partial implementation for input streams, streams that read 8-bit bytes.
         OutputStream provides the API and partial implementation for output streams, streams that write 8-bit bytes.

I/O Superclasses

         Reader and InputStream define similar APIs but for different data types.
         Reader contains these 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)
 
         Writer and OutputStream define similar APIs but for different data types.
         Writer defines these methods for writing characters and arrays of characters:
        int write(int c)
        int write(char cbuf[])
        int write(char cbuf[], int offset, int length)
         OutputStream defines the same methods but for bytes:
        int write(int c)
        int write(byte cbuf[])
        int write(byte cbuf[], int offset, int length)
         All of the streams
        readers, writers
        input streams, output streams
are automatically opened when created.
         You can close any stream explicitly by calling its close method.

How to do I/O

         import java.io.*;
         Open the stream
         Use stream (read, write or both)
        Catch exceptions if needed
         Close the stream

The IOException Class

         Operations performed by the I/O classes may throw an IOException
        A file intended for reading or writing might not exist
        Even if the file exists, a program may not be able to find it
        The file might not contain the kind of data we expect
         An IOException is a checked exception therefore it must be handled

Opening a Stream

         There is data external to your program that you want to get, or you want to put data somewhere outside your program
         When you open a stream, you are making a connection to that external place
         Once the connection is made, you forget about the external place and just use the stream

Example of Opening a Stream
         A FileReader is used to connect to a file that will be used for input:

FileReader fr =     new FileReader(fileName);

         The fileName specifies where the (external) file is to be found
         You never use fileName again; instead, you use fr

int ch;
ch = fr.read( );

         The fr.read() method reads one character and returns it as an integer, or -1 if there are no more characters to read
         The meaning of the integer depends on the file encoding (ASCII, Unicode, other)

Manipulating the Input Data

         Reading characters as integers isn’t usually what you want to do
         A BufferedReader will convert integers to characters; it can also read whole lines
         The constructor for BufferedReader takes a FileReader parameter:
BufferedReader br = new BufferedReader(fr);

Reading Lines

String s;
            s = br.readLine( );
         A BufferedReader will return null if there is nothing more to read

Closing Streams
         A stream is an expensive resource
         There is a limit on the number of streams that you can have open at one time
         You should not have more than one stream open on the same file
         A stream must be closed before it can be opened again
         Always close your streams!

How did I figure that out?
         I wanted to read lines from a file
         I thought there might be a suitable readSomething method, so I went to the API Index
         I found a readLine method in several classes; most promising was the BufferedReader class
         The constructor for BufferedReader takes a Reader as an argument
         Reader is an abstract class, but it has several implementations, including InputStreamReader
         FileReader is a subclass of InputStreamReader
         There is a constructor for FileReader that takes as its argument a (String) file name

Working with Text Files
         Information can be read from and written to text files by declaring and using the correct I/O streams
         The FileReader class represents an input file containing character data
         The FileReader and BufferedReader classes together create a convenient text file output stream
         The FileWriter class represents a text output file, but with minimal support for manipulating data
         Therefore, the PrintWriter class provides print and println methods
 
Text File I/O Streams
         Input
BufferedReader in = new BufferedReader(new FileReader(“foo.in”));
         Output
PrintWriter out = new PrintWriter( new BufferedWriter(new FileWriter("foo.out")));
         BufferedWriter is not necessary but makes things more efficient
         Output streams should be closed explicitly
out.close();

import java.io.*;

public class Copy {
     public static void main(String[] args) {
         String line;
         try {
             BufferedReader in =  new BufferedReader(new FileReader(args[0]));
             PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(args[1])));

            while ((line = in.readLine()) != null) {
                out.println(line);
            }

            in.close();
            out.close();
        } catch (FileNotFoundException e) {
            System.out.println("The file " + args[0] + " was not found.");
        } catch (IOException e) {
            System.out.println(e);
        }
    }
}

Standard I/O Data Streams

         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
         System.in typically represents keyboard input
         System.out and System.err typically represent a particular window on the monitor screen
         We use System.out when we execute println statements

Standard Input

BufferedReader in =   new BufferedReader(new InputStreamReader(System.in));


         InputStreamReader converts the byte input stream to a character input stream
         BufferedReader allows us to use the readLine method to get an entire line of input

import java.io.*;

public class TestIO {

    public static void main(String[] args) {
        double x;
        String y;

        BufferedReader in =  new BufferedReader(new InputStreamReader(System.in));

        try {
            System.out.print(“Enter a floating point value: ”);
            x = Double.parseDouble(in.readLine());

            System.out.print(“Enter some text: ”);
            y = in.readLine();

            System.out.println(x + y);
        } catch (NumberFormatException e) {
            System.out.println(“You did not enter a double.”);
            System.exit(0);
        } catch (IOException e) {
            System.out.println(e);
            System.exit(0);
        }
       
        System.out.println(“Everything was fine.”);
    }
}


Working with Files and Directories

        Earlier we used the File class to create files and directories. In addition, File's methods can be used to delete files, rename files, determine whether files exist, create temporary files, change a file's attributes, and differentiate between files and directories.

We saw earlier that the statement

File f = new File("log.txt");
always creates a File object, and then does one of two things:

1. If "log.txt" does NOT exist, no actual file is created.
2. If "log.txt" does exist, the new File object refers to the existing file.

Notice that File f = new File("log.txt"); NEVER creates an actual file. There are two ways to create a file:

1. Invoke the createNewFile() method on a File object. For example:
File f = new File("log.txt"); // no file yet
f.createNewFile();//make a file, "log.txt" which is assigned to 'f'

2. Create a Reader or a Writer or a Stream. Specifically, create a FileReader, a FileWriter, a PrintWriter, a FileInputStream, or a FileOutputStream. Whenever you create an instance of one of these classes, you automatically create a file, unless one already exists, for instance

File f = new File("log.txt"); // no file yet
PrintWriter pw = new PrintWriter(f); // make a PrintWriter object AND make a file, "log.txt" to which 'f' is assigned, AND assign 'pw' to the PrintWriter

Creating a directory is similar to creating a file. Again, we'll use the convention of referring to an object of type File that represents an actual directory, as a Directory File object, capital D, (even though it's of type File.) We'll call an actual directory on a computer a directory, small d. Phew! As with creating a file, creating a directory is a two-step process; first we create a Directory (File) object, then we create an actual directory using the following mkdir() method:

File myDir = new File("mydir"); // create an object
myDir.mkdir(); // create an actual directory

Once you've got a directory, you put files into it, and work with those files:

File myFile = new File(myDir, "myFile.txt");
myFile.createNewFile();

This code is making a new file in a subdirectory. Since you provide the subdirectory to the constructor, from then on you just refer to the file by its reference variable. In this case, here's a way that you could write some data to the file myFile:

PrintWriter pw = new PrintWriter(myFile);
pw.println("new stuff");
pw.flush();
pw.close();

Be careful when you're creating new directories! As we've seen, constructing a Reader or Writer will automatically create a file for you if one doesn't exist, but that's not true for a directory:

File myDir = new File("mydir");
// myDir.mkdir(); // call to mkdir() omitted!
File myFile = new File(
myDir, "myFile.txt");
myFile.createNewFile(); // exception if no mkdir!

This will generate an exception something like

java.io.IOException: No such file or directory

You can refer a File object to an existing file or directory. For example, assume that we already have a subdirectory called existingDir in which resides an existing file existingDirFile.txt, which contains several lines of text. When you run the following code,

File existingDir = new File("existingDir"); // assign a dir
System.out.println(existingDir.isDirectory());
File existingDirFile = new File(
existingDir, "existingDirFile.txt"); // assign a file
System.out.println (existingDirFile.isFile());
FileReader fr = new FileReader(existingDirFile);
BufferedReader br = new BufferedReader(fr); // make a Reader
String s;
while( (s = br.readLine()) != null) // read data
System.out.println(s);
br.close();
the following output will be generated:
true
true
existing sub-dir data
line 2 of text
line 3 of text

Take special note of the what the readLine() method returns. When there is no more data to read, readLine() returns a null—this is our signal to stop reading the file. Also, notice that we didn't invoke a flush() method. When reading a file, no flushing is required, so you won't even find a flush() method in a Reader kind of class.
In addition to creating files, the File class also let's you do things like renaming and deleting files. The following code demonstrates a few of the most common ins and outs of deleting files and directories (via delete()), and renaming files and directories (via renameTo()):

File delDir = new File("deldir"); // make a directory
delDir.mkdir();
File delFile1 = new File(delDir, "delFile1.txt"); // add file to directory
delFile1.createNewFile();
File delFile2 = new File(delDir, "delFile2.txt"); // add file to directory
delFile2.createNewFile();
delFile1.delete(); // delete a file
System.out.println("delDir is "+ delDir.delete()); // attempt to delete the directory
File newName = new File(delDir, "newName.txt"); // a new object
delFile2.renameTo(newName); // rename file
File newDir = new File("newDir"); // rename directory
delDir.renameTo(newDir);

This outputs:          delDir is false
and leaves us with a directory called newDir that contains a file called newName.txt. Here are some rules that we can deduce from this result:

·          delete() You can't delete a directory if it's not empty, which is why the invocation delDir.delete() failed.
·          renameTo() You must give the existing File object a valid new File object with the new name that you want. (If newName had been null we would have gotten a NullPointerException.)
·          renameTo() It's okay to rename a directory, even if it isn't empty. There's a lot more to learn about using the java.io package, but we only discuss one more thing, that is how to search for a file. Assuming that we have a directory named searchThis that we want to search through, the following code uses the File.list() method to create a String array of files and directories, which we then use the enhanced for loop to iterate through and print:

String[] files = new String[100];
File search = new File("searchThis");
files = search.list(); // create the list
for(String fn : files) // iterate through it
System.out.println("found " + fn);
On our system, we got the following output:
found dir1
found dir2
found dir3
found file1.txt
found file2.txt

Your results will almost certainly vary : )

Sample Programms

A program to convert Numbers into words

import java.io.*;
import java.lang.*;
class NumToWords
{
        public static void main(String a[]) throws IOException
        {
                String s="";
                BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
                System.out.print("Enter filename : ");
                try
                {
                        s=br.readLine();
                }catch(Exception e){}
                InputStream in=new FileInputStream(s);
                MyInputStream mis=new MyInputStream(in);
                mis.changeNumbers();
                in.close();
                mis.close();
        }
}
class MyInputStream extends FilterInputStream
{
        InputStream is;
        MyInputStream(InputStream in)
        {
                super(in);
                is=in;
        }
        public void changeNumbers() throws IOException
        {
                PushbackInputStream pis;
                String num="";
                char ch;
                int c;
                pis=new PushbackInputStream(is);
                while((c=pis.read())!=-1)
                {
                        ch=(char)c;
                        if('0'<=ch&&ch<='9')
                        {
                                num="";
                                while('0'<=ch&&ch<='9'&&c!=-1)
                                {
                                        num=num+ch;
                                        c=pis.read();
                                        ch=(char)c;
                                }
                                System.out.print(MyInputStream.process(num));
                                pis.unread(ch);
                        }
                        else
                                System.out.print(ch);
                }
        }
        static String process(String str)
        {
         String a1[]={"One","Two","Three","Four","Five","Six","Seven","Eight","Nine"};
         String a2[]={"Twenty","Thirty","Fourty","Fifty","Sixty","Seventy","Eighty","Ninety"};
         String a3[]={"Ten","Eleven","Twelve","Thirteen","Fourteen","Fifteen","Sixteen","Seventeen",   "Eighteen","Nineteen"};
         String a4[]={"Hundered","Thousand","Lakhs","Crores"};
                int num=0;
                try
                {
                        num=Integer.parseInt(str);
                }catch(Exception e){}
                if(num==0)
                        return "Zero";
                int n,n1;
                String ans="";
                String ans1="";
                n1=num%10;
                num=num/10;
                if(n1!=0)
                        ans=a1[n1-1];
                if(num>0)
                {
                        n=num%10;
                        num=num/10;
                        if(n==1)
                                ans=a3[n1];
                        else if(n!=0)
                                ans=a2[n-2]+" "+ans;
                }
                if(num>0)
                {
                        n=num%10;
                        num=num/10;
                        if(n!=0)
                                ans=a1[n-1]+" "+a4[0]+" "+ans;
                }
                for(int i=1;num>0;i++)
                {
                        n1=num%10;
                        num=num/10;
                        if(n1!=0)
                                ans1=a1[n1-1];
                        if(num>0)
                        {
                                n=num%10;
                                num=num/10;
                                if(n==1)
                                        ans1=a3[n1];
                                else if(n!=0)
                                        ans1=a2[n-2]+" "+ans1;
                        }
                        ans=ans1+" "+a4[i]+" "+ans;
                        ans1="";
                }
                return(ans);
        }
}