Super detailed interpretation of JAVA I/O stream (Beginner's read through version)

Posted by nikky_d16 on Thu, 20 Jan 2022 23:18:22 +0100

This paper is based on horse soldier JAVA teaching video https://www.bilibili.com/video/BV1Ff4y147WP?p=257&spm_id_from=pageDriver Learning writing

catalogue

1, Introduction of File class

2, File operations on files

2, File operation on Directory

3, Introduction of I/O flow

4, FileReader reads file contents

5, Handling exceptions with try catch finally

6, FileInputStream reads the contents of the file

8, Buffered byte stream processor

9, Transform stream - InputStreamReader,OutputStreamWriter

10, Exercise: keyboard input output to text file

11, Data stream - DataInputStream,DataOutputStream

12, Object stream - serialization and deserialization

1, Introduction of File class

Manipulate files / directories in java? What should I do?

The most typical feature of JAVA is object-oriented. JAVA is also good at operating objects. Therefore, we should encapsulate the files and folders on the disk into objects. The objects belong to the File class. With this object, our program can directly operate the files and create and delete the files.

2, File operations on files

 public static void main(String[] args) throws IOException {
        //Encapsulate the File as an object of File class
        File f = new File("src\\main\\resources\\test.txt");
        //It is recommended to use file Separator, get splices
        File f2 = new File("C:" + File.separator + "webapp\\test\\src\\main\\resources\\test.txt");
        //common method
        System.out.println("Is the file readable" + f.canRead());
        System.out.println("Is the file writable" + f.canWrite());
        System.out.println("File name" + f.getName());
        System.out.println("File parent directory" + f.getParent());
        System.out.println("Is it a directory" + f.isFile());
        System.out.println("Is it a file" + f.isDirectory());
        System.out.println("Hide" + f.isHidden());
        System.out.println("file size" + f.length());
        System.out.println("Does it exist " + f.exists());
        if (f.exists()) {
 //           f.delete();
        } else {
            f.createNewFile();
        }
        System.out.println(f == f2);
        System.out.println(f.equals(f2));            //Compare file paths
    }

2, File operation on Directory

public static void main(String[] args) {
        File f = new File("C:\\webapp\\test\\src\\main\\resources");
        System.out.println("Is the file readable" + f.canRead());
        System.out.println("Is the file writable" + f.canWrite());
        System.out.println("File name" + f.getName());
        System.out.println("File parent directory" + f.getParent());
        System.out.println("Is it a directory" + f.isFile());
        System.out.println("Is it a file" + f.isDirectory());
        System.out.println("Hide" + f.isHidden());
        System.out.println("file size" + f.length());
        System.out.println("Does it exist " + f.exists());

        //Methods for directories
        File f2 = new File("C:\\webapp\\test\\src\\main\\resources\\a\\b\\c");
        //Create directory
        //f2.mkdirs();
        //Delete, deleting the directory will only delete one layer, and make sure there is nothing
        //f2.delete();
        //Query,
        String[] list = f.list();  //Array of directory / file names under the folder
        for(String s:list){
            System.out.println(s);
        }
        File[] files = f.listFiles();//More extensive role
        for(File file:files){
            System.out.println(file.getName()+","+file.getAbsolutePath());
        }
    }

3, Introduction of I/O flow

I/O is used to process the direct data transmission of the equipment

Image understanding: I/O flow is regarded as a "pipe":

I/O flow architecture (orange is the key):

4, FileReader reads file contents

Case: copy files through JAVA

Function breakdown 1: file program: FileReader

Read the contents of the file into the program character by character:

  public static void main(String[] args) throws IOException {
        //Document procedure:
        //1. There is a File -- "create a File class"
        File f = new File("src\\main\\resources\\test.txt"); //Content: abc teacher

        //2. Connect the "pipe" to the source file by using the FileReader stream -- create a FileReader stream object
        FileReader fr = new FileReader(f);

        //3. Perform the action of "sucking" -- read the file
        /*The following code verifies that if the end of the file is reached, the read content is - 1
        int n1 = fr.read();
        int n2 = fr.read();
        int n3 = fr.read();
        int n4 = fr.read();
        int n5 = fr.read();
        int n6 = fr.read();
        System.out.println(n1);
        System.out.println(n2);
        System.out.println(n3);
        System.out.println(n4);
        System.out.println(n5);
        System.out.println(n6);*/

        //Mode 1:
        /*int n = fr.read();
        while (n!=-1){
            System.out.println(n);
            n = fr.read();
        }*/

        //Mode 2:
        int n;
        while ((n=fr.read())!=-1){
            System.out.print((char) n);
        }

        //4. If the "pipe" is not used, close the flow
        //Streams, databases and network resources cannot be shut down by the JVM itself. At this time, they must be shut down manually by the programmer
        fr.close();
    }

Want to read five characters at a time. If not enough, read five characters next time

 public static void main(String[] args) throws IOException {
        //Document procedure:
        //1. There is a File -- "create a File class"
        File f = new File("src\\main\\resources\\test.txt"); //Content: abc teacher

        //2. Connect the "pipe" to the source file by using the FileReader stream -- create a FileReader stream object
        FileReader fr = new FileReader(f);

        //3. Perform the action of "sucking" -- read the file
        //Introduce a "courier's car", which pulls five express at a time
        char[] ch = new char[5];  //Buffer array
        int len = fr.read(ch);//Read 5 at a time: the return value is the effective length in the array

        while (len!=-1){
            //System.out.println(len);
           /* Mode 1:
           for(int i=0;i<len;i++)
                System.out.print(ch[i]);*/
           //Mode 2:
            String str = new String(ch,0,len);
            System.out.print(str);
            len = fr.read(ch);
        }
        //4. If the "pipe" is not used, close the flow
        fr.close();
    }

Function breakdown 2: program file: FileReader

Character by character output:

    public static void main(String[] args) throws IOException {
        //1. There is an objective document
        File f = new File("src\\main\\resources\\demo.txt");

        //2. Use the FileWriter stream to connect this "pipe" to the source file
        FileWriter fw = new FileWriter(f);

        //3. Start action: output action
        //One character one character output
        String str = "hello Hello";
        for(int i=0;i<str.length();i++){
            fw.write(str.charAt(i));
        }

        //4. Close the flow
        fw.close();
    }

Discovery: if the target file does not exist, it will be created automatically.

If the target file exists, new FileWriter(f) is equivalent to overwriting the source file. The operation is the same as new FileWriter(f,false), and new FileWriter(f,true) means to append later rather than overwrite.

Output with buffer array:

  public static void main(String[] args) throws IOException {
        //1. There is an objective document
        File f = new File("src\\main\\resources\\demo.txt");

        //2. Use the FileWriter stream to connect this "pipe" to the source file
        FileWriter fw = new FileWriter(f,true);

        //3. Start action: output action
        //One character one character output
        String str = ",Hello China";
        char[] chars = str.toCharArray();
        fw.write(chars);

        //4. Close the flow
        fw.close();
    }

Function breakdown 3: use FileReader and filewriter to copy files

    public static void main(String[] args) throws IOException {

        //1. There is a source file
        File f1 = new File("src\\main\\resources\\test.txt");
        //2. There is an objective document
        File f2 = new File("src\\main\\resources\\demo.txt");

        //3. Connect an input pipe to the source file:
        FileReader fr = new FileReader(f1);
        //4. Create an output pipe and connect it to the target file
        FileWriter fw = new FileWriter(f2);
        //5. Start action
        //Method 1: copy one character by one:
        /*int n = fr.read();
        while (n!=-1){
            fw.write(n);
            n = fr.read();
        }*/

        //Method 2: use buffered character array:
       /* char[] ch = new char[5];
        int len = fr.read(ch);
        while (len!=-1){
            fw.write(ch,0,len);
            len = fr.read(ch);
        }*/

       //Method 3: write out the buffer array as a string
        char[] ch = new char[5];
        int len = fr.read(ch);
        while (len!=-1){
            String s = new String(ch,0,len);
            fw.write(s);
            len = fr.read(ch);
        }

        //4. Close the flow (when closing the flow, follow the backward closing, and then close it first)
        fw.close();
        fr.close();
    }

!!! Warning: do not use character stream to manipulate non text files

Text file: txt  . java  . c  . cpp -- "character stream operation is recommended

Non text file: jpg .mp3 .mp4 .doc .ppt -- "byte stream operation is recommended

5, Handling exceptions with try catch finally

public static void main(String[] args) {
        //1. There is a source file
        File f1 = new File("src\\main\\resources\\test.txt");
        //2. There is an objective document
        File f2 = new File("src\\main\\resources\\demo.txt");
        //3. Connect the pipe to the source file:
        FileReader fr = null;
        FileWriter fw = null;
        try {
            fr = new FileReader(f1);
            fw = new FileWriter(f2);
            //4. Start action
            char[] ch = new char[5];
            int len = fr.read(ch);
            while (len!=-1){
                String s = new String(ch,0,len);
                fw.write(s);
                len = fr.read(ch);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //5. Close the flow
            try {
                if(fw!=null) //Prevent null pointer exceptions
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(fr!=null)
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

6, FileInputStream reads the contents of the file

1. Read text file:

public static void main(String[] args) throws IOException {
        //1. There is a source file
        File f = new File("src\\main\\resources\\test.txt");
        //2. Connect a byte stream pipe to the source file
        FileInputStream fis = new FileInputStream(f);
        //3. Start reading files
        /*
        * Detail 1:
        * The file is stored in utf-8, so the bottom layer of English characters actually occupies 1 byte
        * However, for Chinese characters, the bottom layer actually occupies 3 bytes.

        * Detail 2:
        * If the file is a text file, do not use byte stream to read. It is recommended to use character stream
        *
        * Detail 3: read() reads a byte, but do you find that the return value is Int type instead of byte type?
        * read The bottom layer of the method is processed so that the returned data are positive numbers
        * If the byte returns - 1, is it the read byte or the end of the file?
        * */
        int n = fis.read();
        while (n!=-1){
            System.out.println(n);
            n = fis.read();
        }
        //4. Close the flow
        fis.close();
    }

2. Using byte stream to read non text files: (taking pictures as an example:) -- "reading byte by byte is inefficient

public static void main(String[] args) throws IOException {
        //1. There is a source file
        File f = new File("src\\main\\resources\\Red dead.png");
        //2. Connect a byte stream pipe to the source file
        FileInputStream fis = new FileInputStream(f);
        //3. Start reading files
        int count = 0; //Counter, counting the number of bytes read
        int n = fis.read();
        while (n!=-1){
            count++;
            n = fis.read();
        }
        System.out.println(count);
        //4. Close flow
        fis.close();
    }

3. Buffer array using byte type:

    public static void main(String[] args) throws IOException {
        //1. There is a source file
        File f = new File("src\\main\\resources\\Red dead.png");
        //2. Connect a byte stream pipe to the source file
        FileInputStream fis = new FileInputStream(f);
        //3. Start reading files
        //Using buffer array: (courier's car)
        int count = 0;
        byte[] b = new byte[1024*6];
        int len = fis.read(b); //len is the effective length of the read
        while (len!=-1){
           // System.out.println(len);
            count += len;
            len = fis.read(b);
        }
        System.out.println(count);
        //4. Close the flow
        fis.close();
    }

7, FileInputStream,FileOutput complete non text copy

1. Read in a byte and write out a byte

    public static void main(String[] args) throws IOException {
        //1. There is a source file
        File f1 = new File("src\\main\\resources\\Red dead.png");
        //2. There is an objective document
        File f2 = new File("src\\main\\resources\\Red dead1.png");
        //3. Connect a byte stream pipe to the source file
        FileInputStream fis = new FileInputStream(f1);
        //4. There is an output pipe connected to the wooden plaque file
        FileOutputStream fos = new FileOutputStream(f2);
        //5. Start copying: (reading and writing)
        int n = -1;
        while ((n=fis.read())!=-1){
            fos.write(n);
        }
        //4. Close the flow
        fos.close();
        fis.close();
    }

Time consuming: 2147ms

2. Use buffer array (much faster)

    public static void main(String[] args) throws IOException {
        //1. There is a source file
        File f1 = new File("src\\main\\resources\\Red dead.png");
        //2. There is an objective document
        File f2 = new File("src\\main\\resources\\Red dead1.png");
        //3. Connect a byte stream pipe to the source file
        FileInputStream fis = new FileInputStream(f1);
        //4. There is an output pipe connected to the wooden plaque file
        FileOutputStream fos = new FileOutputStream(f2);
        //5. Start copying: (reading and writing)
        //Using buffer array
        byte[] b = new byte[1024*8];
        int len = fis.read(b);
        while (len!=-1){
            fos.write(b,0,len);
            len = fis.read(b);
        }
        //4. Close the flow
        fos.close();
        fis.close();
    }

Time: 2ms

8, Buffered byte stream processor

To achieve the above effects, FileInputStream and fileoutputstream alone cannot be completed. At this time, the function needs to be strengthened. This strengthening requires the introduction of a new stream (another layer of stream outside FileInputStream and fileoutputstream): bufferedinputstream, bufferedoutputstream, ------- > processing stream

    public static void main(String[] args) throws IOException {
        //1. There is a source file
        File f1 = new File("src\\main\\resources\\Red dead.png");
        //2. There is an objective document
        File f2 = new File("src\\main\\resources\\Red dead1.png");
        //3. Connect a byte stream pipe to the source file
        FileInputStream fis = new FileInputStream(f1);
        //4. There is an output pipe connected to the wooden plaque file
        FileOutputStream fos = new FileOutputStream(f2);
        //5. The function is enhanced. A tube is sleeved outside the FileInputStream: BufferedInputStream;
        BufferedInputStream bis = new BufferedInputStream(fis);
        //6. The function is enhanced. Set another tube outside the FileOutputStream: BufferedOutputStream;
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        //7. Start
        byte[] b = new byte[1024*6];
        int len = bis.read(b);
        while (len!=-1){
            bos.write(b,0,len);
            len = bis.read(b);
        }
        //8. Close the flow
        //If the processing stream wraps the node stream, the byte stream will be closed as long as the high-level stream is closed
        bos.close();
        bis.close();
    }

Time: 1ms

9, Transform stream - InputStreamReader,OutputStreamWriter

Function: convert byte stream and character stream.

Is it a byte stream or a character stream? Belongs to character stream

InputStreamReader: input stream of bytes -- input stream of characters

OutputStreamWriter: output stream of characters -- output stream of bytes

1. Convert the input byte stream into the input character stream, and then complete the file -- "program:

    public static void main(String[] args) throws IOException {
        //1. There is a source file
        File f = new File("src\\main\\resources\\test.txt");
        //2. An input byte stream contact file is required:
        FileInputStream fis = new FileInputStream(f);
        //3. Add a conversion stream to convert byte stream into character stream: (the conversion stream belongs to a processing stream)
        //When converting bytes into characters, you need to specify an encoding that is consistent with the encoding format of the file itself
        //If the coding format is not uniform, the effect displayed on the console will be garbled
        //InputStreamReader isr = new InputStreamReader(fis,"utf-8");
        //Get the code of the program itself -- utf-8
        InputStreamReader isr = new InputStreamReader(fis);
        //4. Start the action and display the contents of the file on the console:
        char[] ch = new char[20];
        int len = isr.read(ch);
        while (len!=-1){
            System.out.print(new String(ch,0,len));
            len = isr.read(ch);
        }
        //Close flow
        isr.close();
    }

2. Convert the stream to copy the text file

    public static void main(String[] args) throws IOException {
        //1. There is a source file
        File f1 = new File("src\\main\\resources\\test.txt");
        //2. There is an objective document
        File f2 = new File("src\\main\\resources\\test1.txt");
        //3. Input direction
        FileInputStream fis = new FileInputStream(f1);
        InputStreamReader isr = new InputStreamReader(fis,"utf-8");
        //4. Output direction
        FileOutputStream fos = new FileOutputStream(f2);
        OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");

        //5. Start action
        char[] ch = new char[20];
        int len = isr.read(ch);
        while (len!=-1){
            osw.write(ch,0,len);
            len = isr.read(ch);
        }
        //6. Close the flow
        osw.close();
        isr.close();
    }

10, Exercise: keyboard input output to text file

 public static void main(String[] args) throws IOException {
        //1. Prepare the input direction and enter it with the keyboard
        InputStream in = System.in;
        //Byte stream - character stream
        InputStreamReader isr = new InputStreamReader(in);
        //Set a buffer stream outside the isr
        BufferedReader br = new BufferedReader(isr);
        //2. Prepare the output direction:
        //Prepare target file
        File f = new File("src\\main\\resources\\test2.txt");
        FileWriter fw = new FileWriter(f);
        BufferedWriter bw = new BufferedWriter(fw);
        //3. Start action
        String s = br.readLine();           //Waiting for keyboard entry is a blocking method
        while (!s.equals("exit")){
            bw.write(s);
            bw.newLine();
            s = br.readLine();
        }
        //4. Close the flow
        bw.close();
        br.close();
    }

11, Data stream - DataInputStream,DataOutputStream

Data flow: used to manipulate basic data types and strings

DataInputStream: writes the basic data types and strings stored in the file to memory variables

DataOutputStream: writes variables of basic data types and strings in memory to a file

Code: write out variables using DataOutputStream

    public static void main(String[] args) throws IOException {
        DataOutputStream dos = new DataOutputStream(new FileOutputStream(new File("src\\main\\resources\\test3.txt")));
        dos.writeUTF("Hello");
        dos.writeBoolean(false);
        dos.writeDouble(6.9);
        dos.writeInt(82);

        dos.close();

    }

result

Program read in

        DataInputStream dis = new DataInputStream(new FileInputStream(new File("src\\main\\resources\\test3.txt")));
        System.out.println(dis.readUTF());
        System.out.println(dis.readBoolean());
        System.out.println(dis.readDouble());
        System.out.println(dis.readInt());

        //Close flow
        dis.close();

Output results:

Verification: we can't understand the file, but the program can understand it

Requirement: write out type and read in type must match! And the reading order shall be consistent.

12, Object stream - serialization and deserialization

Object stream: a processing stream used to store and read basic data type data or objects. Its strength is that it can write objects in JAVA to the data source and restore objects from the data source.

Serialization and deserialization:

ObjectOutputStream class: converts JAVA objects in memory into platform independent binary data, allowing such binary data to be permanently saved on disk or transmitted to another network node through the network. - -- serialize

Use ObjectInputStream class: when other programs get this binary data, they can restore it to the original Java object Deserialization

Code: manipulating string objects

First, write a string object to the file

    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("src\\main\\resources\\test4.txt")));
        oos.writeObject("Hello");
        oos.close();
    }

View file:

We can't understand the contents of the file, but the program can be understood, so we can write a program to read the contents of the file:

        //Read the string saved in the file into memory
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("src\\main\\resources\\test4.txt")));
        //read
        String s = (String) ois.readObject();
        System.out.println(s);
        //Close flow
        ois.close();

Output results:

Code: manipulating custom class objects

Custom Person class:

public class Person {

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

Test class:

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //Serialization: object in memory -- File
        //There is one object:
        Person p = new Person("lili",19);
        //With object flow:
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("src\\main\\resources\\test5.txt")));
        //Write out:
        oos.writeObject(p);
        //Close flow
        oos.close();
    }

Runtime exception

Cause of abnormality:

The class corresponding to the object to be serialized must implement the interface

There is nothing inside the interface. This interface is called identification interface. It plays the role of identification. What is it? Only the objects of the classes that practice this interface can be serialized.

Modify the Person class to (implement interface)

public class Person implements Serializable {

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

Test: it is found that the serialization is successful, and Person has the ability of serialization.

We can't understand the binary data, but the program can understand it, so we can use the program to realize the deserialization operation and restore the object to memory.

Test:

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("src\\main\\resources\\test5.txt")));
        //Read into memory:
        Person person = (Person) ois.readObject();
        System.out.println(person.getName());
        //Close flow
        ois.close();

Print results:

It is proved that the deserialization is successful, and the binary data is stored in memory

serialVersionUID:

All classes that implement the Serializable interface have a static constant that represents the serialized version identifier

:

private static final long serialVersionUID;

serialVersionUID is used to indicate the compatibility between different versions of a class. It is simple but far away. Its purpose is to use serialized objects for version control, and to determine whether each version is compatible during deserialization.

If the class does not display the definition of this static variable, its value is automatically generated by the JAVA runtime environment according to the internal details of the class. If the instance variable of the class is modified, the serialVersionUID may change. Therefore, it is recommended to display the statement.

In short, the serialization mechanism of JAVA verifies the consistency of the version by judging the serialVersionUID of the class at runtime. During deserialization, the JVM will compare the serialVersionUID in the transmitted byte stream with the serialVersionUID of the corresponding local entity class. If it is the same, it is considered to be consistent and can be deserialized, Otherwise, an exception with inconsistent serialization version will occur.

I now add the toString method to the person class:

public class Person implements Serializable {

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Result of running again: exception in thread "main" Java io. InvalidClassException: Person; local class incompatible: stream classdesc serialVersionUID = -873572521303181536, local class serialVersionUID = -7418736053376735269

There is no toString method during serialization. Now toString is added to this class, resulting in a mismatch problem.

Solution: add a serial number to the class

After adding the serial number, regenerate the version without toString method, add toString method, and execute the following code:

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("src\\main\\resources\\test5.txt")));
        //Read into memory:
        Person person = (Person) ois.readObject();
        System.out.println(person.toString());
        //Close flow
        ois.close();

Output:

Automatically configure serial number in IDEA

Check the selected option in the figure. On the Person class, Alt + enter to generate.

Details:

1. All internal attributes of the class to be sequenced must be Serializable (the basic data types are Serializable, but the user-defined object must implement the Serializable interface)

2.static,transient modified attributes cannot be serialized.

Topics: Java