File I/O
A file that prints itself...
ReadMe.java |
1 | import java.io.FileReader; |
2 | import java.io.IOException; |
3 | |
4 | public 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:
- FileReader - This is fairly intuitive. You pass a file name to its constructor and then use it to read files.
- 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.
- 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.
- 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 |
1 | import java.io.FileWriter; |
2 | import java.io.IOException; |
3 | |
4 | public 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 |
1 | import java.io.PrintWriter; |
2 | import java.io.FileWriter; |
3 | import java.io.IOException; |
4 | |
5 | public 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 |
1 | import java.io.*; |
2 | |
3 | public 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 |
1 | import java.io.*; |
2 | |
3 | public 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 |
1 | import java.io.*; |
2 | |
3 | public 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 IOException, ClassNotFoundException { |
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 IOException, ClassNotFoundException { |
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
|
- InputStream/OutputStream - These are older methods of doing I/O that are based on
streams of bytes rather than characters.
- implements Serializable - An interface. More on that in a later lesson.
- ObjectOutputStream - Turns any Serializable object into a stream of bytes.
- ObjectInputStream - Takes a stream of appropriately formatted bytes and turns
it into an object.
ReadInput.java |
1 | import java.io.*; |
2 | |
3 | public 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
|
|