File I/O - 2020
The java.io package provides an extensive library of classes for dealing with input and output. Java provides stream as a general mechanism for data I/O
Stream implements sequential access of data. There are two kinds of streams: byte streams (binary streams) and character streams (text streams).
An input stream is an object that an application can use to read a sequence of data, and an output stream is an object that an application can use to write a sequence of data. An output stream is an object that an application can use to write a sequence of data. An input stream acts acts as a source of data, and an output acts as a destination of data.
Here's a summary of the I/O classes:
- File
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 us 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 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 us to get the next line of characters from a file. - 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. The BufferedWriter class also provides a newLine() method 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), we might find that we can use PrintWrite in places where we 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. - Console
This new, Java 6 convenience class provides methods to read input from the console and write formatted output to the console.
The File with a capital F is an object of type File which is used to represent the actual file.
import java.io.*; public class WriteA { public static void main(String[] args) { File file = new File("fileA.txt"); } }
After the run, we do not have any file called fileA.txt in our current directory. When we make a new instance of the class File, we're not yet making an actual file, but we're just creating a filename.
Once we have a File object, there are several ways to make an actual file. Here is one example:
import java.io.*; public class WriteA { public static void main(String[] args) { try { boolean actualFile = false; File file = new File("fileA.txt"); System.out.println(file.exists()); // (1) actualFile = file.createNewFile(); System.out.println(actualFile); // (2) System.out.println(file.exists()); // (3) } catch (IOException e) { e.printStackTrace(); } } }
With an output:
false true true
Line (1) returned false because
new File()does not create a file on the disk. Actual file is created on the line
actualFile = file.createNewFile();So, on line (2), we get true and on line (3), we call exists() which returns true.
If we run the same program again, we get true from exists() call because the actual file is there. Then when we call createNewFile() on file:
actualFile = file.createNewFile();we get false since the method doesn't create a file. From the last call to exists(), it returns true.
In this example we used File's methods:
- boolean exists()
This method returns true if it can find the actual file - boolean createNewFile()
This method creates a new file if it doesn't already exist.
Usually we use FileWriter and FileReader with wrapper. But let's look at the example how we can use them.
import java.io.*; public class WriteB { public static void main(String[] args) { char [] in = new char[1024]; int size = 0; try { File file = new File("fileB.txt"); FileWriter fw = new FileWriter(file); fw.write( "If there were in the world today\n" + "any large number of people\n" + "who desired their own happiness\n" + "more than they desired the unhappiness of others,\n" + "we could have paradise in a few years.\n" + "-Bertrand Russell\n"); fw.flush(); fw.close(); FileReader fr = new FileReader(file); size = fr.read(in); System.out.print(size + " characters\n"); for(int i = 0; i < size ; i++) System.out.print(in[i]); fr.close(); } catch (IOException e) { e.printStackTrace(); } } }
Output is:
199 characters If there were in the world today any large number of people who desired their own happiness more than they desired the unhappiness of others, we could have paradise in a few years. -Bertrand Russell
Let's look at the code in detail.
FileWriter fw = new FileWriter(file);The line does:
- It creates a FileWriter reference, fw.
- It creates a FileWriter object and assigns it to fw.
- It creates an empty file on the disk.
fw.write("God does not play dice.\n"); fw.flush(); fw.close();After writing the file, we do flush() and then close().
When we write data out to a stream, some amount of buffering will occur. We never know for sure when the last of the data will actually be sent. We may have to perform many write operation on a stream before closing it.
Invoking the flush() method guarantees that the last of the data we thought we had already written actually gets out to the file. Whenever we're done using a file, either reading it or writing to it, we should invoke the close() method. When we are doing file I/O, we're using expensive and limited operation system resources. So, when we're done, invoking close() will free up the resources.
FileReader fr = new FileReader(file);We make a new FileReader object, which also opened the file on disk for reading.
size = fr.read(in);The read() method read the whole file, a character at a time, and put it into the char[] in.
for(int i = 0; i < size ; i++) System.out.print(in[i]);We print out the number of characters we read, then we close the file.
Java's entire I/O was designed around the idea of using several classes in combination. Combining I/O classes is sometimes called wrapping or 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 and the classes are designed to be combined with each other in several ways to handle a wide range of situations.
Class | Extends From | Constructor Arguments | Method |
---|---|---|---|
File | Object | (File, String) (String) (String, String) | createNewFile() delete() exists() isDirectory() isFile() list() mkdir(0) renameTo() |
FileWriter | Writer | (File) (String) | close() flush() write() |
BufferedWriter | Writer | (Writer) | close() flush() write() newLine() |
PrintWriter | Writer | (File) (String) (OutputStream) (Writer) | close() flush() write() format() printf() print() println() |
FileReader | Reader | (File) (String) | read() |
BufferedReader | Reader | (Reader) | read() readLine() |
Let's modify above example using BufferedReader and its method readLine(). We get the same output.
import java.io.*; public class WriteB { public static void main(String[] args) { try { File file = new File("fileB.txt"); FileWriter fw = new FileWriter(file); PrintWriter pw = new PrintWriter(fw); pw.println("If there were in the world today"); pw.println("any large number of people"); pw.println("who desired their own happiness"); pw.println("more than they desired the unhappiness of others,"); pw.println("we could have paradise in a few years."); pw.println("-Bertrand Russell"); pw.flush(); pw.close(); FileReader fr = new FileReader(file); BufferedReader buffer = new BufferedReader(fr); String line = ""; while( (line = buffer.readLine()) != null) System.out.print(line + "\n"); buffer.close(); } catch (IOException e) { e.printStackTrace(); } } }
Creating a directory is similar to creating a file.
import java.io.*; public class WriteB { public static void main(String[] args) { try { File dir = new File("dir"); dir.mkdir(); File file = new File(dir,"myfile.txt"); file.createNewFile(); PrintWriter pw = new PrintWriter(file); pw.println("If you optimize everything, you will always be unhappy. "); pw.println("-Donald Knuth "); pw.flush(); pw.close(); FileReader fr = new FileReader(file); BufferedReader buffer = new BufferedReader(fr); String line = ""; while( (line = buffer.readLine()) != null) System.out.print(line + "\n"); buffer.close(); } catch (IOException e) { e.printStackTrace(); } } }
Output from the run should look like this:
If you optimize everything, you will always be unhappy. -Donald Knuth
The "myfile.txt" can be located "./dir/myfile.txt"
import java.io.Console; public class ConsoleA { public static void main(String[] args) { Console csl = System.console(); if(csl != null) { char[] passwd; passwd = csl.readPassword("%s", "password: "); for(char c: passwd) csl.format("%c ",c); csl.format("\n"); MyTool mt = new MyTool(); String item; while(true) { item = csl.readLine("%s", "input?: "); csl.format("output: %s \n", mt.doIt(item)); } } else { System.out.println("Couldn't get Console"); } } } class MyTool { String doIt(String arg) { return "result is " + arg; } }
Output should look like this:
C:\javadir> java ConsoleA password: s e c r e t input?: do not try output: result is do not try input?:
The java.io.Console is new to Java 6. The console is the physical device with a keyboard and a display. If you're running Java SE 6 from the command line, you'll have access to a console object, to which you can get a reference by invoking System.console(). It's possible for or Java program to be running in an environment that doesn't have access to a console object, so be sure that our invocation of System.colsole() actually returns a valid console reference and not null.
Console csl = System.console(); if(csl != null) {
The Console class makes it easy to accept input from the command line, both echoed and nonechoed, and makes it easy to write formatted output to the command line.
The readLine() method returns a string containing whatever the user keyed in. However, the readPassword() method doesn't return a string: it returns a character array. That's because once we've got the password, we can verify it and then absolute remove it from memory. If a string was returned, it could exist in a pool somewhere in memory and this may open up a door to some potential abuse.
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization