The Java byte stream and character stream summary of the interview avoidance manual IO stream!

Speaking of receiving input values

In daily development and applications, sometimes it is necessary to directly receive input values ​​from external devices such as keyboards. For this data receiving method, we generally have three methods: byte stream reading, character stream reading, Scanner tool class Read.

Byte stream read

Just look at an example:

public class Demo01SystemIn {
    public static void main(String[] args) throws IOException {
        int a = System.in.read();
        System.out.println(a);
        char c = 'a';
        System.out.println((int) c);
    }
}

After running the program, it will be blocked by the read method. At this time, enter a character a in the console, then the above program will output 97 in both sentences. This is no problem, because the lowercase letter a corresponds to 97, then if we enter a Chinese What will happen? 【references】

Modify the a in the above example to medium, and then run the program. In the same input in the console, you will get 228 and 200113, which means that we haven't read all the input in the console, because read can only read 1 byte, in order to further verify the conclusion, we will rewrite the above example:

public class Demo01SystemIn {
    public static void main(String[] args) throws IOException {
        char a = (char) System.in.read();//读取一个字节
        System.out.println(a);
        char c = '中';
        System.out.println(c);
    }
}

After running, the following results are obtained:


As you can see, the first output is garbled, because System.in.read() can only read one byte at a time, and Chinese occupies 3 bytes under utf-8 encoding. Just because the read method can only read one byte at a time, its range can only be between -1 and 255, and -1 means the end has been read. 【references】

So what should I do if I want to read Chinese completely?

Character stream reading

Let's first look at the following example:

public class Demo01SystemIn {
    public static void main(String[] args) throws IOException {
        InputStreamReader inputStreamReader1 = new InputStreamReader(System.in);
        int b = inputStreamReader1.read();//只能读一个字符
        System.out.println(b);

        InputStreamReader inputStreamReader2 = new InputStreamReader(System.in);
        char[] chars = new char[2];
        int c = inputStreamReader2.read(chars);//读入到指定char数组,返回当前读取到的字符数
        System.out.println("读取的字符数为:" + c);
        System.out.println(chars[0]);
        System.out.println(chars[1]);
    }
}//加入Java开发交流君样:756584822一起吹水聊天

After running, the output result is as follows: at


this time we can already read a character, of course, sometimes in order to optimize, we need to use BufferedReader for further packaging:

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
Although this method solves the problem of garbled reading in Chinese, it is not very convenient to use, so generally we will use Scnner to read keyboard input information. .

Scanner read

Scanner actually encapsulates System.in and provides a series of methods to read different character types, such as nextInt, nextFloat, and next.

public class Demo02Scnner {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextInt()){
            System.out.println(scanner.nextInt());
        }
    }//加入Java开发交流君样:756584822一起吹水聊天
}

What is IO stream

Stream is an abstract concept, which represents the unstructured transmission of data (taken from Baidu Encyclopedia). The IO stream corresponds to InPut and Output, that is, input and output. The concept of input and output is specific to the application. For example, if the content in the file needs to be read in the current program, then this is the input, and if the data of the application itself needs to be sent to other applications, it corresponds to the output. 【references】

Byte stream and character stream

According to the processing method of the stream, the stream can be divided into two types: byte stream and character stream.

Byte stream

The basic unit of byte stream reading is byte, which uses ASCII encoding and is usually used to process binary data. Its top-level abstract classes are InputStream and OutputStream. For example, System.in in the above example actually obtains an InputStream class .

The stream family in Java is very large and provides a lot of streams with different functions. In practical applications, we can choose different combinations to achieve our goals.

Byte input stream

The figure below is a schematic diagram of the family relationship of byte input streams:


from the figure above, these structures are very clear. First is a top-level interface, and second is a basic stream with different functions. For example, our most commonly used FileInputStream is used to read. File, there is a FilterInputStream stream, this stream is mainly used to extend the basic stream function, it itself simply covers all the methods in the parent class InputStream, and does not do any special processing, the real function extension needs to rely on Many of its subclasses, such as the most commonly used BufferedInputStream provides data buffering, thereby improving the efficiency of reading the stream, and DataInputStream can be used to process binary data and so on. 【references】

By combining these streams with many different functions, we can flexibly read the data we need. For example, when we need to read a binary file, then we need to use DataInputStream, and DataInputStream itself does not have the function of directly reading the contents of the file, so we need to combine FileInputStream:

FileInputStream fin = new FileInputStream("E:\\test.txt");
DataInputStream din = new DataInputStream(fin);
System.out.println(din.readInt());

At the same time, if we want to use the buffering mechanism, we can further assemble the BufferedInputStream:

FileInputStream fin = new FileInputStream("E:\\test.txt");
DataInputStream din = new DataInputStream(new BufferedInputStream(fin));
System.out.println(din.readInt());

There is another interesting stream, PushbackInputStream, which can push the read data back into the stream:

public class Demo03 {
    public static void main(String[] args) throws IOException {
        FileInputStream fin = new FileInputStream("E:\\test.txt");//文档内存储 abcd
        PushbackInputStream pin = new PushbackInputStream(new BufferedInputStream(fin));
//加入Java开发交流君样:756584822一起吹水聊天
        int a = pin.read();//读取到a
        System.out.println(a);
        if (a != 'b'){
            pin.unread(a);//将 a 推回流中
        }
        System.out.println(pin.read());//再次读取到 a
        System.out.println(pin.read());//读取到 b
        System.out.println(pin.read());// 读取到 c
    }
}

Byte output stream

The following figure is a schematic diagram of the family relationship between byte output streams:


this structure is basically similar to the structure of the input stream, and we can also achieve different outputs through combination.

For example, for ordinary output files, you can use the FileOutputStream stream:

FileOutputStream fout = new FileOutputStream("E:\\test2.txt");
fout.write(1);
fout.write(2);

If you want to output binary format, then you can combine DataOutputStream streams:

FileOutputStream fout = new FileOutputStream("E:\\test2.txt");
DataOutputStream dout = new DataOutputStream(fout);
dout.write(9);//加入Java开发交流君样:756584822一起吹水聊天
dout.write(10);

Principle of Buffer Stream

IO operation is a relatively time-consuming operation, and the read method of byte stream can only return one byte at a time, so when we need to read multiple bytes, it will appear that every read requires an IO operation. The buffer stream defines a byte array with a size of 8192. When we use the buffer stream, when we read the data, we will read at most 8192 bytes into the memory at a time, and then return one by one. It greatly reduces the number of IOs; similarly, when writing data, the buffer stream will write the data to the memory first, and when we finish writing the data that needs to be written, it will be refreshed to the specified location, such as disk, at one time. 【references】

Character stream

The basic unit of character stream reading is a character, which uses Unicode encoding, and its read method returns a Unicode code element (0~65535). 【references】

Character streams are usually used to process text data, and the top-level abstract classes are Reader and Write. For example, the InputStreamReader in the first example in the text is inherited from the Reader class.

Character input stream

The following figure is a schematic diagram of the family relationship of the character input stream:


As can be seen from the figure above, in addition to the top-level Reader class, the character stream also provides some basic character streams to process text data. For example, we need to read content from text:

public class Demo05Reader {
    public static void main(String[] args) throws Exception {
        //字节流
        FileInputStream fin = new FileInputStream("E:\\test.txt");//文本内容为“双子孤狼”
        System.out.println(fin.read());//372
        //字符流
        //加入Java开发交流君样:756584822一起吹水聊天
        InputStreamReader ir = new InputStreamReader(new FileInputStream("E:\\test.txt"));//文本内容为“双子孤狼”
        System.out.println(ir.read());//21452
        char s = '双';
        System.out.println((int)s);//21452
    }
}

The difference can be clearly seen after the output, the byte stream reads one byte at a time, and the character stream reads one character at a time.

Of course, we can also use free combination to read characters more flexibly. For example, we can combine BufferedReader to read a whole line of data:

public class Demo05Reader {
    public static void main(String[] args) throws Exception {
        InputStreamReader ir = new InputStreamReader(new FileInputStream("E:\\test.txt"));//文本内容为“双子孤狼”
        BufferedReader br = new BufferedReader(ir);
        String s;
        while (null != (s = br.readLine())){
            System.out.println(s);//输出双子孤狼
        }
    }
}

Character output stream

The following figure is a schematic diagram of the family relationship of the character output stream: For


text output, the one we use most is PrintWriter. I think most of my friends have used this category:

public class Demo06Writer {
    public static void main(String[] args) throws Exception{
        PrintWriter printWriter = new PrintWriter("E:\\test3.txt");
        printWriter.write("双子孤狼");
        printWriter.flush();
    }
}

The difference between this and byte stream is that you need to manually call the flush method after writing, otherwise the data will be lost and will not be written to the file.

Why does the character stream need flush, but the byte stream does not

The byte stream does not need flush operation because the byte stream directly manipulates bytes, without any conversion in the middle, so you can directly manipulate the file, and the character stream, in the final analysis, the bottom layer is the byte stream, but the character stream Help us convert bytes into characters. This conversion depends on the character table, so after the characters and bytes are converted, they need to be flushed to the disk through the flush operation. 【references】

It should be noted that the flush method is also provided in the top-level class OutputStream of the byte output stream, but it is an empty method. If required by subclasses, the flush method can also be implemented.

RandomAccessFile

RandomAccessFile is a random access file class, which can find or write data anywhere in the file.

public class Demo07RandomAccessFile {
    public static void main(String[] args) throws Exception {
        //文档内容为 lonely wolf
        RandomAccessFile inOut = new RandomAccessFile(new File("E:\\test.txt"),"rw");
        System.out.println("当前指针在:" + inOut.getFilePointer());//默认在0
        System.out.println((char) inOut.read());//读到 l
        System.out.println("当前指针在:" + inOut.getFilePointer());
        inOut.seek(7L);//指针跳转到7的位置
        System.out.println((char) inOut.read());//读到 w
        inOut.seek(7);//跳回到 7
        //加入Java开发交流君样:756584822一起吹水聊天
        inOut.write(new byte[]{'c','h','i','n','a'});//写入 china,此时 wolf被覆盖
        inOut.seek(7);//继续跳回到 7
        System.out.println((char) inOut.read());//此时因为 wolf 被 china覆盖,所以读到 c
    }
}

According to the output results in the above example, you can see that the RandomAccessFile class can randomly assign pointers and read and write randomly, which is very powerful.

In addition, it should be noted that when constructing RandomAccessFile, a mode needs to be passed in. There are four main modes:

  • r: Read-only mode. Calling any write related methods at this time will throw an IOException.
  • rw: Read and write mode. Supports reading and writing, if the file does not exist, it will be created.
  • rws: Read and write mode. Whenever a write operation is performed, the content or metadata is flushed to the disk synchronously.
  • rwd: Read and write mode. Whenever a write operation is performed, the changed content will be flushed to the disk synchronously.

to sum up

This article mainly sorts out the IO stream in Java, and establishes a global concept of IO stream in Java by dividing it into byte stream and character stream, as well as input stream and output stream, to establish a global concept of IO stream in Java. Finally, some examples are used to demonstrate How to combine different types of streams to achieve powerful and flexible input and output. Finally, RandomAccessFile, which supports both input and output, is introduced.


The latest high-frequency interview questions collected in 2021 (all organized into documents), there are a lot of dry goods, including mysql, netty, spring, thread, spring cloud, jvm, source code, algorithm and other detailed explanations. There are also detailed learning plans and interviews. Question sorting, etc. For those who need to obtain these contents, please add Q like: 756584822

Insert picture description here

【references】