Java.io in nutshell: 22 case studies
This post attempts to cover a comprehensive set of operations in java.io. Compared with other books and blogs related to this topic, my motivation is to show “how-to” through case studies. As once a Java student, I realize the most effective way of learning a new program language is through examples: copy and paste a piece of codes, run it to see results, then try to modify and re-run it step-by-step. Therefore, I assume this post will be helpful.
It is worth noting that this post will not touch anything related to java.nio because I think it is quite a different topic.
Table of Contents
- Case 0: Create a new file
- Case 1: Two constants in File
- Case 2: Delete a file
- Case 3: Create a directory
- Case 4: List files and directories in a given directory
- Case 5: Tests whether a file is a file
- Case 6: Write to a RandomAccessFile
- Case 7: Write bytes to a file
- Case 8: Append bytes to a file
- Case 9: Read bytes from a file
- Case 10: Copy files
- Case 11: Write chars to a file
- Case 12: Read chars from a file
- Case 13: Convert from OutputStream to FileWriter
- Case 14: Convert from InputStream to FileReader
- Case 15: Use pipeline
- Case 16: Write formatted string to a file
- Case 17: Redirect the “standard” IO
- Case 18: Read a file line by line
- Case 19: Compress to a zip file
- Case 20: Extract from a zip file
- Case 21: Push back bytes
Case 0: Create a new file
import java.io.File; public class FileOperationTest { public static void main(String[] args) { File f = new File("helloworld.txt"); try { f.createNewFile(); } catch (Exception e) { e.printStackTrace(); } } }
Output: a new and empty file is created in the working directory, iff there is no “helloword.txt” before.
Case 1: Two constants in File
import java.io.File; public class FileOperationTest { public static void main(String[] args) { System.out.println(File.separator); System.out.println(File.pathSeparator); } }
Output:
/ :
I get the above output because I am working on Linux. If you use Windows, the output should be \
and ;
. As can be seen, for the purpose of portability and robustness, it should always be recommended to use these two constants.
Case 2: Delete a file
import java.io.File; public class FileOperationTest { public static void main(String[] args) { File f = new File("helloworld.txt"); if (f.exists()) { if (!f.delete()) { System.out.println("the file cannot be deleted."); } } else { System.out.println("the file does not exist."); } } }
Case 3: Create a directory
import java.io.File; public class FileOperationTest { public static void main(String[] args) { File f = new File("hello"); f.mkdir(); } }
Case 4: List files and directories in a given directory
import java.io.File; public class FileOperationTest { public static void main(String[] args) { File f = new File("."); for (String str : f.list()) { System.out.println(str); } } }
Output: I am using Eclipse
.settings .classpath .project src bin
File.list() returns an array of strings. If you prefer an array of Files, please use File.listFiles():
import java.io.File; public class FileOperationTest { public static void main(String[] args) { File f = new File("."); for (File subFile : f.listFiles()) { System.out.println(subFile.getName()); } } }
Case 5: Tests whether a file is a file
import java.io.File; public class FileOperationTest { public static void main(String[] args) { File f = new File("helloworld.txt"); if (f.isFile()) { System.out.println("YES"); } else { System.out.println("NO"); } } }
Combined with File.listFiles(), we can list all files in the given directory and its sub-directories.
import java.io.File; public class FileOperationTest { public static void main(String[] args) { File f = new File("."); listFiles(f); } private static void listFiles(File f) { if (f.isFile()) { System.out.println(f.getName()); return; } for (File subFile : f.listFiles()) { listFiles(subFile); } } }
Output: compared with Case 4 to see the difference
org.eclipse.jdt.core.prefs .classpath .project FileOperationTest.java FileOperationTest.class
Case 6: Write to a RandomAccessFile
import java.io.IOException; import java.io.RandomAccessFile; public class FileOperationTest { public static void main(String[] args) throws IOException { RandomAccessFile file = new RandomAccessFile( "helloworld.txt", "rw"); file.writeBytes("hello world!"); file.writeChar('A'); file.writeInt(1); file.writeBoolean(true); file.writeFloat(1.0f); file.writeDouble(1.0); file.close(); } }
If you open the file using text editor, you will find garbled code except the first hello world!A
(kindly note the char A
at the end of “hello world!”). This is because RandomAccessFile only writes an array of bytes in the file.
Case 7: Write bytes to a file
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class FileOperationTest { public static void main(String[] args) throws IOException { OutputStream out = new FileOutputStream( "helloworld.txt"); String str = "hello world!"; out.write(str.getBytes()); out.close(); } }
This time you can see “hello world!” in the file. Of course you can write to an OutputStream byte by byte, but it is less effective:
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class FileOperationTest { public static void main(String[] args) throws IOException { OutputStream out = new FileOutputStream( "helloworld.txt"); String str = "hello world!"; for (byte b : str.getBytes()) { out.write(b); } out.close(); } }
Case 8: Append bytes to a file
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class FileOperationTest { public static void main(String[] args) throws IOException { OutputStream out = new FileOutputStream( "helloworld.txt", true); String str = "hello world!"; out.write(str.getBytes()); out.close(); } }
Output: hello world!hello world!
Case 9: Read bytes from a file
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class FileOperationTest { public static void main(String[] args) throws IOException { InputStream in = new FileInputStream("helloworld.txt"); byte[] bs = new byte[1024]; int len = -1; while ((len = in.read(bs)) != -1) { System.out.println(new String(bs, 0, len)); } in.close(); } }
The InputStream.read() will return -1 if it reaches the end of the file. Otherwise, it will return the total number of bytes read into the buffer.
Case 10: Copy files
Simply combine Case 7 and 9, we will get the copy function.
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class Copy { public static void main(String[] args) throws IOException { if (args.length != 2) { System.out.println("java Copy SOURCE DEST"); System.exit(1); } InputStream input = new FileInputStream(args[0]); OutputStream output = new FileOutputStream(args[1]); int len = 0; byte bs[] = new byte[1024]; while ((len = input.read(bs)) != -1) { output.write(bs, 0, len); } input.close(); output.close(); } }
Case 11: Write chars to a file
import java.io.FileWriter; import java.io.IOException; import java.io.Writer; public class FileOperationTest { public static void main(String[] args) throws IOException { Writer out = new FileWriter("helloworld.txt"); String str = "hello world!"; out.write(str); out.close(); } }
For the above case, you will get the same result as in Case 7. So what is the difference? FileWriter is meant for writing streams of characters. It will use the default character encoding and the default byte-buffer size. In other words, it is a wrapper class of FileOutputStream for convenience. Therefore, to specify these values yourself, consider using a FileOutputStream.
Case 12: Read chars from a file
import java.io.FileReader; import java.io.IOException; import java.io.Reader; public class FileOperationTest { public static void main(String[] args) throws IOException { Reader in = new FileReader("helloworld.txt"); char cs[] = new char[1024]; int len = -1; while ((len = in.read(cs)) != -1) { System.out.println(new String(cs, 0, len)); } in.close(); } }
Whether to use streams of bytes or characters? It really depends. Both have buffers. InputStream/OutputStream provide more flexibility, but will make your “simple” program complex. On the other hand, FileWriter/FileReader give a neat solution but you lose the control.
Case 13: Convert from OutputStream to FileWriter
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; public class FileOperationTest { public static void main(String[] args) throws IOException { Writer out = new OutputStreamWriter( new FileOutputStream("helloworld.txt")); out.write("hello world!"); out.close(); } }
Instead of using default character encoding, you can specify the charset. For example,
Writer out = new OutputStreamWriter( new FileOutputStream("helloworld.txt"), "utf8");
Case 14: Convert from InputStream to FileReader
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; public class FileOperationTest { public static void main(String[] args) throws IOException { Reader in = new InputStreamReader( new FileInputStream("helloworld.txt")); char cs[] = new char[1024]; int len = -1; while ((len = in.read(cs)) != -1) { System.out.println(new String(cs, 0, len)); } in.close(); } }
Case 15: Use pipeline
The following code creates two thread, a Producer which writes something into the pipeline at one end and a Consumer which reads it from the pipeline at the other end. To create a pipeline, we need to create PipedInputStream and PipedOutputStream seperately, and connect them using output.connect(input)
or via their constructors. In this program, I intentionally start the Consumer thread first and ask the whole program to sleep 1 second before starting the Producer thread. This will show the pipeline DOES work. It is worthy noting that, I close the pipeline in the Producer because “A thread that writes to a stream should always close the OutputStream before terminating.” If we remove the out.close()
line, an IOException will be thrown
java.io.IOException: Write end dead at java.io.PipedInputStream.read(PipedInputStream.java:311) at java.io.PipedInputStream.read(PipedInputStream.java:378) at java.io.InputStream.read(InputStream.java:101) at foo.Consumer.run(FileOperationTest.java:58) at java.lang.Thread.run(Thread.java:701)
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; public class FileOperationTest { public static void main(String[] args) throws IOException, InterruptedException { PipedInputStream input = new PipedInputStream(); PipedOutputStream output = new PipedOutputStream(); output.connect(input); Producer producer = new Producer(output); Consumer consumer = new Consumer(input); new Thread(consumer).start(); Thread.sleep(1000); new Thread(producer).start(); } } class Producer implements Runnable { private final OutputStream out; public Producer(OutputStream out) { this.out = out; } @Override public void run() { String str = "hello world!"; try { out.write(str.getBytes()); out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } } } class Consumer implements Runnable { private final InputStream in; public Consumer(InputStream in) { this.in = in; } @Override public void run() { byte[] bs = new byte[1024]; int len = -1; try { while ((len = in.read(bs)) != -1) { System.out.println(new String(bs, 0, len)); } } catch (IOException e) { e.printStackTrace(); } } }
Case 16: Write formatted string to a file
PrintStream adds functionality to print representations of various data values conveniently. The format string syntax is almost same as C.
import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; public class FileOperationTest { public static void main(String[] args) throws IOException { PrintStream print = new PrintStream( new FileOutputStream("helloworld.txt")); print.printf("%s %s!", "hello", "world"); print.close(); } }
Case 17: Redirect the “standard” IO
In Java, both standard and error output are PrintStreams. The standard input is InputStream. Therefore we can reassign them freely. The following code redirect the standard output to error output.
public class FileOperationTest { public static void main(String[] args) { System.out.println("hello world!"); System.setOut(System.err); System.out.println("hello world!"); } }
Output: In Eclipse, red text means error message
hello world!hello world!
Case 18: Read a file line by line
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class FileOperationTest { public static void main(String[] args) throws IOException { BufferedReader reader = new BufferedReader( new FileReader("helloworld.txt")); String str = null; while ((str = reader.readLine()) != null) { System.out.println(str); } reader.close(); } }
Case 19: Compress to a zip file
import java.io.FileOutputStream; import java.io.IOException; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; public class FileOperationTest { public static void main(String[] args) throws IOException { ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream( "helloworld.zip")); String str = "hello world!"; for (int i = 0; i < 3; i++) { zipOut.putNextEntry(new ZipEntry("helloworld" + i + ".txt")); zipOut.write(str.getBytes()); zipOut.closeEntry(); } zipOut.close(); } }
The above code creates a zip file and puts three files, named “helloworld0.txt”, “helloworld1.txt”, and “helloworld2.txt”, each of which contains the content “hello world!”.
Case 20: Extract from a zip file
import java.io.FileInputStream; import java.io.IOException; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; public class FileOperationTest { public static void main(String[] args) throws IOException { ZipInputStream zipIn = new ZipInputStream(new FileInputStream( "helloworld.zip")); ZipEntry entry = null; byte bs[] = new byte[1024]; while ((entry = zipIn.getNextEntry()) != null) { // get file name System.out.printf("file: %s content: ", entry.getName()); int len = -1; // read current entry to the buffer while((len=zipIn.read(bs)) != -1) { System.out.print(new String(bs, 0, len)); } System.out.println(); } zipIn.close(); } }
Output:
file: helloworld0.txt content: hello world! file: helloworld1.txt content: hello world! file: helloworld2.txt content: hello world!
Case 21: Push back bytes
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.PushbackInputStream; public class FileOperationTest { public static void main(String[] args) throws IOException { PushbackInputStream push = new PushbackInputStream( new ByteArrayInputStream("hello, world!".getBytes())); int temp = 0; while ((temp = push.read()) != -1) { if (temp == ',') { push.unread('.'); } System.out.print((char) temp); } } }
The above code pushes a dot after reading a comma, therefore the output is
hello,. world!
However, if you try to push more characters back such as push.unread("(...)".getBytes());
, you will get an IOException: Push back buffer is full. This is because the default size of the pushback buffer is 1. To specify it with larger capacity, use the constructor PushbackInputStream(InputStream in, int size)
, such as
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.PushbackInputStream; public class FileOperationTest { public static void main(String[] args) throws IOException { PushbackInputStream push = new PushbackInputStream( new ByteArrayInputStream("hello, world!".getBytes()), 10); int temp = 0; while ((temp = push.read()) != -1) { if (temp == ',') { push.unread("(...)".getBytes()); } System.out.print((char) temp); } } }
Output:
hello,(...) world!
I’m afraid to say that the guava library (especially com.google.common.io.Files) makes many of these redundant…
true. this post is mostly for beginners.
Nice collection of cases. But may I suggest to improve the examples to not lure beginners into thinking that a conversion between bytes and String is ok without excplicit encoding? This applies to String.getBytes(), as well as for all the constructors of Reader or Writer you use. Just yesterday we had to waste three hours for an encoding bug hunt where a Reader was opened without explicit encoding. It worked on Linux but not on Windows, because the default encoding is different. One further comment regarding IOExceptions. You define your main() methods as throwing an IOException. This gets you around… Read more »