1. "Hello, World!"
  2. Variables and Types
  3. Arrays
  4. While, If, For
  5. ...Problem Set 0
  6. Static Methods
  7. Static Fields
  8. String Conversion
  9. Objects
  10. Threading
  11. Strings
  12. ...Problem Set 1.5
  13. Packages
  14. Complex Numbers
  15. Abstract classes
  16. Interfaces
  17. Autoboxing
  18. ...Problem Set 1
  19. enum
  20. Inner Classes
  21. Polymorphism
  22. Tanks!
  23. Callbacks
  24. Exceptions
  25. File I/O
  26. ...Problem Set 2
  27. Regular Expressions

File I/O

A file that prints itself...

ReadMe.java
1import java.io.FileReader;
2import java.io.IOException;
3 
4public class ReadMe {
5    public static void main(String[] args) throws IOException {
6        FileReader fr = new FileReader(args[0]);
7        char[] buf = new char[1024];
8        int nchars = 0;
9        StringBuffer sb = new StringBuffer();
10        while((nchars = fr.read(buf,0,buf.length)) > 0) {
11            sb.append(buf,0,nchars);
12        }
13        fr.close();
14        System.out.println(sb.toString());
15    }
16}
$ javac ReadMe.java
$ java ReadMe ReadMe.java
import java.io.FileReader;
import java.io.IOException;
 
public class ReadMe {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader(args[0]);
        char[] buf = new char[1024];
        int nchars = 0;
        StringBuffer sb = new StringBuffer();
        while((nchars = fr.read(buf,0,buf.length)) > 0) {
            sb.append(buf,0,nchars);
        }
        fr.close();
        System.out.println(sb.toString());
    }
}

Hopefully, by this point, very little needs to be explained. You understand about importing, exceptions, using "new" to create objects, using and StringBuffer to build strings.

What's new:

  1. FileReader - This is fairly intuitive. You pass a file name to its constructor and then use it to read files.
  2. int read(char[] cbuf,int off,int len) - this method is used ot extract an array of characters from the Reader. The argument "off" is short for "offset" and tells us at which index of the cbuf array to start depositing characters. The argument "len" is short for length and tells us the maximum number of characters to try and read at one time. We need to give this upper bound to avoid ArrayIndexException.
  3. The expression "(nchars = fr.read(buf,0,buf.length)" reads from the FileReader and assigns the result to an integer named "nchars." This is surrounded with parenthesis so that the whole operation will be evaluated as an integer and then compared with zero.
  4. void append(char[] cbuf,int start,int end) - this is similar to the read method, but "start" and "end" identify which characters from cbuf to append to the String we are building.
WriteMe.java
1import java.io.FileWriter;
2import java.io.IOException;
3 
4public class WriteMe {
5    public static void main(String[] args) throws IOException {
6        FileWriter fw = new FileWriter("tst.out");
7        String s = "Hello file system!\n";
8        char[] ca = s.toCharArray();
9        fw.write(ca,0,ca.length);
10        fw.close();
11        ReadMe.main(new String[]{"tst.out"});
12    }
13}
$ javac WriteMe.java
$ java WriteMe
Hello file system!

This is a bit ugly looking -- we had to extract a char array from a String, then tell write which sub-chunk of the array to write. We also had to use the special code for newline "\n".

WriteMe2.java
1import java.io.PrintWriter;
2import java.io.FileWriter;
3import java.io.IOException;
4 
5public class WriteMe2 {
6    public static void main(String[] args) throws IOException {
7        FileWriter fw = new FileWriter("tst.out");
8        PrintWriter pw = new PrintWriter(fw);
9        pw.println("Hello file system!");
10        pw.close();
11        ReadMe.main(new String[]{"tst.out"});
12    }
13}
$ javac WriteMe2.java
$ java WriteMe2
Hello file system!

The Java I/O library was designed to be used like plumbing, you fit parts together in a sequence and then use them. In this case, we are fitting the PrintWriter pipe on the front of the FileWriter object. The result is that we get the convenient println() method we have come to know and love.

We could have used this plumbing trick on our ReadMe example. Let's revisit it now:

ReadMe2.java
1import java.io.*;
2 
3public class ReadMe2 {
4    public static void main(String[] args) throws IOException {
5        FileReader fr = new FileReader(args[0]);
6        BufferedReader br = new BufferedReader(fr);
7        for(String s=br.readLine();s != null;s=br.readLine())
8            System.out.println(s);
9    }
10}
$ javac ReadMe2.java
$ java ReadMe2 ReadMe2.java
import java.io.*;
 
public class ReadMe2 {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader(args[0]);
        BufferedReader br = new BufferedReader(fr);
        for(String s=br.readLine();s != null;s=br.readLine())
            System.out.println(s);
    }
}

BufferedReader is used for more than just the convenience of the readLine() method. Reading and writing from disk is slow (in computer terms), and so we like to do it infrequently. Getting data out of memory is much quicker and it is okay to retrieve it in smaller chunks.

Imagine if you had to drive an hour to buy groceries. You would tend to stock up on things. Maybe you would buy one hundred cans of soup and put them in your pantry. It's much quicker and easier to get them from the pantry than the store. Your pantry is like a memory buffer. You can quickly obtain bytes from there while it is much slower to obtain them from disk -- hence the BufferedReader takes in large chunks of data at a time and stores them up.

There is also a BufferedWriter class. We haven't used it in these examples, but it is just another segment of pipe that you can use in creating a Writer object (remember, the Internet is not a truck, it's pipes!).

Copy.java
1import java.io.*;
2 
3public class Copy {
4    public static void main(String[] args) throws IOException {
5        FileReader fr = new FileReader(args[0]);
6        BufferedReader br = new BufferedReader(fr);
7 
8        FileWriter fw = new FileWriter(args[1]);
9        BufferedWriter bw = new BufferedWriter(fw);
10        PrintWriter pw = new PrintWriter(bw);
11        for(String s=br.readLine();s != null;s=br.readLine())
12            pw.println(s);
13 
14        pw.close(); // finishes writing output. Without this,
15            // maybe nothing will happen!
16    }
17}
$ javac Copy.java
$ java Copy Copy.java xxx.txt
$ java ReadMe2 xxx.txt
import java.io.*;
 
public class Copy {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader(args[0]);
        BufferedReader br = new BufferedReader(fr);
 
        FileWriter fw = new FileWriter(args[1]);
        BufferedWriter bw = new BufferedWriter(fw);
        PrintWriter pw = new PrintWriter(bw);
        for(String s=br.readLine();s != null;s=br.readLine())
            pw.println(s);
 
        pw.close(); // finishes writing output. Without this,
            // maybe nothing will happen!
    }
}

Now for the coolest most useful trick ever....

Cool.java
1import java.io.*;
2 
3public class Cool implements Serializable {
4    String name;
5    int value;
6 
7    Cool(String name,int value) {
8        this.name = name;
9        this.value = value;
10    }
11 
12    // Save this object to a file
13    public void saveMe(String file) throws IOExceptionClassNotFoundException {
14        FileOutputStream fout = new FileOutputStream(file);
15        BufferedOutputStream bout = new BufferedOutputStream(fout);
16        ObjectOutputStream oout = new ObjectOutputStream(bout);
17        oout.writeObject(this);
18        oout.close();
19    }
20 
21    // Load this object from a file
22    public static Cool loadMe(String file) throws IOExceptionClassNotFoundException {
23        FileInputStream fin = new FileInputStream(file);
24        BufferedInputStream bin = new BufferedInputStream(fin);
25        ObjectInputStream oin = new ObjectInputStream(bin);
26        Object o = oin.readObject();
27        oin.close();
28        return (Cool)o;
29    }
30 
31    public static void main(String[] args) throws Exception {
32        String file = "cool.jo";
33        Cool c = new Cool("Coolio",44);
34        c.saveMe(file);
35        Cool c2 = Cool.loadMe(file);
36        System.out.println(c2.name+"/"+c2.value);
37    }
38}
$ javac Cool.java
$ java Cool
Coolio/44
  1. InputStream/OutputStream - These are older methods of doing I/O that are based on streams of bytes rather than characters.
  2. implements Serializable - An interface. More on that in a later lesson.
  3. ObjectOutputStream - Turns any Serializable object into a stream of bytes.
  4. ObjectInputStream - Takes a stream of appropriately formatted bytes and turns it into an object.
ReadInput.java
1import java.io.*;
2 
3public class ReadInput {
4    public static void main(String[] args) throws IOException {
5        // Input comes from a byte stream, tell java how
6        // how characters are encoded and make a reader
7        InputStreamReader isr = new InputStreamReader(System.in,"ASCII");
8        BufferedReader br = new BufferedReader(isr);
9        System.out.print("input: ");
10        System.out.println(br.readLine());
11    }
12}
$ javac ReadInput.java
$ echo hello world | java ReadInput
input: hello world