The most important function of a computer is to process data. A useful computer language needs to have good IO capabilities so that unprocessed data flows into the program and processed data flows out.
Compared with other languages, Java's IO functions are complex. In other languages, many IO functions (such as reading files) are encapsulated and can be implemented with one or two lines of programs. In Java, programmers often need multiple levels of decoration to achieve file reading.
The benefit of relative complexity is the flexibility of IO. In Java, programmers can control the entire process of IO to design the best IO method. We'll see more below.
IO example
Below is the file file.txt I used for demonstration
Hello World!Hello Nerd!
Let's first study an example of file reading:
import java.io.*;public class Test{ public static void main(String[] args) { try { BufferedReader br = new BufferedReader(new FileReader("file.txt")); String line = br.readLine(); while (line != null) { System.out.println(line); line = br.readLine(); } br.close(); } catch(IOException e) { System.out.println("IO Problem"); } }}
This program contains a try...catch...finally exception handler. Please refer to Java Advanced Tutorial on Exception Handling
Decorators and function combinations
The key to program IO is to create a BufferedReader object br:
BufferedReader br = new BufferedReader(new FileReader("file.txt"));
During the creation process, we first created a FileReader object. The function of this object is to read the byte stream from the file "file.txt" and convert it into a text stream. In Java, the standard text encoding is unicode. BufferedReader() receives the FileReader object, expands the functions of FileReader, and creates a new BufferedReader object. In addition to the above-mentioned file reading and conversion functions, this object also provides cached reading (buffered) functions. Finally, we can read the file line by line by calling the readLine() method on the br object.
(Cache reading is to open an area in the memory as a cache, which stores the text stream read by FileReader. When the cache content is read (such as the readLine() command), the cache will load the subsequent text stream.)
BufferedReader() is a decorator that receives a primitive object and returns a decorated object with more complex functions. The benefit of decorators is that they can be used to decorate different objects. What we are modifying here is the text stream read from the file. Other text streams, such as standard input, network transmission streams, etc., can be modified by BufferedReader() to achieve cached reading.
The diagram below shows how br works, with data flowing from bottom to top:
The above decoration process is very similar to the text stream idea in Linux. In Linux, we use a function-like approach to process and pass text streams. In Java, we use decorators. But their purposes are similar, which is to achieve modularization and free combination of functions.
more combinations
In fact, Java provides a rich set of decorators. FileReader combines the two steps of reading and conversion, and adopts commonly used default settings, such as unicode for encoding. We can use the combination of FileInputStream + InputStreamReader to replace FileReader, thus separating the two steps of reading bytes and converting, and having better control over the two processes.
(Of course, FileReader is more convenient to use. InputStreamReader converts FileInputStream into a Reader for processing unicode text)
Arrows indicate the direction of data flow
Stream reading and writing come from four base classes: InputStream, OutputStream, Reader and Writer. InputStream and Reader handle reading operations, and OutputStream and Writer handle writing operations. They are both located in the java.io package. The inheritance relationship is as follows:
java.io
In addition, IOException has the following derived classes:
IOException
Reader and Writer and their derived classes handle unicode text. As we see Buffered Reader, InputStreamReader or FileReader.
InputStream and OutputStream and their derived classes handle byte streams. The data in the computer can be considered in byte form, so InputStream and OutputStream can be used to process a wider range of data. For example, we can use the following combination to read the data (such as integers) contained in the compressed file:
Arrows indicate the direction of data flow
We read the byte stream from the compressed file, then decompress it, and finally read the data.
write
Write operations are similar to read operations. We can implement complex writing functions by using decorations. Here is a simple example of writing text:
import java.io.*;public class Test{ public static void main(String[] args) { try { String content = "Thank you for your fish."; File file = new File("new.txt"); / / create the file if doesn't exists if (!file.exists()) { file.createNewFile(); } FileWriter fw = new FileWriter(file.getAbsoluteFile()); BufferedWriter bw = new BufferedWriter(fw); bw.write(content); bw.close(); } catch(IOException e) { System.out.println("IO Problem"); } }}
The file object is created above for processing file paths.
Summarize
This is just a basic introduction to Java IO. Java's IO is relatively complex. Java programmers need to spend some time getting familiar with the classes in java.io and their functionality.