Java Basic IO Stream Study Notes

Please add a picture description

1. What is an IO stream

I: Refers to input (input): read external data (data from storage devices such as disks and CDs) into the program (memory).
O: Refers to output (output): output program (memory) data to storage devices such as disks, CDs, etc.
So the IO stream is the input and output stream, and the stream is centered on the program. What goes into the program is the input stream, and goes outside the program The most important thing is the output stream (such as people drinking water).
The most important part of the IO stream is to know when to choose which stream! ! !

Two. File class

Understand some common File class APIs before understanding IO streams

1. Create a file

	1.绝对路径直接创建:
		String filePath = "e:\\new1.txt";	
		File file = new File(filePath);		//创建文件对象,相当于只在内存里面创建,还跟磁盘没有发生关系
		file.createNewFile();                                 //然后调用创建文件的方法(写入到磁盘)
	2.父目录文件加子路径创建:
		File parentFile = new File("e:\\");
		String fileName = "new2.txt";
		File file = new File(parentFile,fileName);
		file.createNewFile(); 
	3.父目录加子路径构建:
		String parentFile = new File("e:\\");
		String fileName = "new2.txt";
		File file = new File(parentFile,fileName);
		file.createNewFile(); 

2. Commonly used APIs of the File class

		File file = new File("e:\\new1.txt");          创建文件对象
		调用相应方法得到对应信息
		file.getName();			//得到文件名字
		file.getAbsolutePath();	//文件绝对路径
		file.getParent();		//文件父级目录
		file.length();			//文件大小(字节)
		file.exists();			//文件是否存在
		file.isFile();			//是不是一个文件
		file.isDirectory();		//是不是一个文件夹
		创建删除文件夹:
		if(file.exists){file.mkdir();}	//只能创建一级目录("e:\\ddd")
		if(file.exists){file.mkdirs();}	//可以在多级目录下创建,所以一般都用这个
		if(file.exists){file.delete();}	//如果文件存在,删除文件(在java中目录也是特殊文件)

3. Stream Classification

	1.按操作数据单位不同分为:字节流(8 bit)二进制文件,字符流(按字符)文本文件
	2.按数据流的流向不同分为:输入流,输出流
	3.按流的角色的不同分为:节点流,处理流/包装流
	
	IO流由以下四部分顶级基类组成
	输入流:字符输入流(Reader),字节输入流(InputStream)
	输出流:字符输出流(Writer),字节输出流(OutputStream)
	
	选用什么流的话具体看传输的是什么东西,比如二进制文件(音频,视频
	,docx,pdf等等用字节流,因为用字符流的话文件很容易损坏,像文本文档之类的用字符流效率更高)

Four. Some commonly used streams

The difference between node flow and processing flow:

Flow is divided into node flow and processing flow according to function:

  • Node stream: It can read and write data from a specific data source, such as FileReader and FileWriter, which are underlying streams/low-level streams, directly connected to the data source.
  • The processing stream (also called packaging stream) is "connected" to the existing stream (node ​​stream or processing stream), providing programs with more powerful read and write functions and more flexibility, such as BufferedReader and BufferedWriter. The node stream can not only eliminate the implementation differences of different node streams, but also provide a more convenient method to complete the input and output, wrap the node stream, use the decorator design pattern, and will not directly connect to the data source (equivalent to the node stream wrapped in one layer)

The function of processing streams is mainly reflected in the following two aspects:

  • Performance improvement: mainly by increasing buffering to improve the efficiency of input and output.
  • Convenience of operation: The processing flow may provide a series of convenient methods to input and output a large amount of data at one time, which is more flexible and convenient to use

Below is a visual diagram of all node flows and processing flows
Please add a picture description

Commonly used subclasses of InputStream (byte input stream)

1. FilelnputStream:

Example:

1.第一种读取文件的方式:read()无参,一个字节一个字节地读,效率低,一般不用
		String filePath = "e:\\hello.txt";
        int readDate = 0 ;						 //临时存放数据
        FileInputStream fileInputStream = null;            			 //这样定义是为了提升作用域,不然finally里面拿不到fileInputStream对象
       	 try {
    
    
        	fileInputStream = new FileInputStream(filePath);		//创建FileInputStream对象,用于读取文件
          	while ((readDate=fileInputStream.read())!=-1){
    
    		//每读取一个字节输出一个字节  当没有下一个值时返回-1
             		System.out.print((char)readDate);			//如果文本里面有中文会出现乱码,因为一个中文占3个字节,而一次只读取一个字节
        			}
     		  } catch (IOException e) {
    
    
         			e.printStackTrace();
       		        }finally {
    
    
         				fileInputStream.close();				//读取完一定要关闭流,不然很占用资源
      			 }
2.第二种读取方式:read(byte [ ] b)    一次最多读取b.length长度的字节,读不到返回-1(通常用这种!!!!)   
		String filePath = "e:\\hello.txt";
        int readLen = 0 ;					 //存放字节长度
        byte[] buf = new byte[8];   //一次读取八个字节
		FileInputStream fileInputStream = null;            			
       		try {
    
    
        			fileInputStream = new FileInputStream(filePath);		
         			while ((readLen=fileInputStream.read(buf))!=-1){
    
    		//每读取8个字节,返回整数8,最后一次返回最后一次读取了多少字节的整数,没读取到返回负1
             			System.out.print(new String(buf,0,readLen));		//String(字节数组,从哪个索引开始读取,读取字节的长度)
        			}
     			} catch (IOException e) {
    
    
         				 	  e.printStackTrace();
       			}finally {
    
    
         				fileInputStream.close();				
      			 }

2.BufferedInputStream:

Buffer flow, any node flow can be placed in the constructor, and a layer is wrapped outside, which is more efficient.
Use Cases:

    @Test
    public void bufferedInputStream() throws IOException {
    
    
        String path = "f:\\s.txt";
        int readLen = 0;
        byte[] buf = new byte[1024];
        BufferedInputStream bi = new BufferedInputStream(new FileInputStream(path));
        while ((readLen=bi.read(buf))!= -1){
    
    
            System.out.println(new String(buf,0,readLen));
        }
        bi.close();                             //这里底层会去实现FileReader.close()方法
    }

3.ObjectInputStream:

look at a demand

1. Save the int data of int num = 100 to the file, note that it is not 10 numbers, but int 100, and can directly restore int 100 from the file 2. Set Dog dog
= new Dog("Xiaohuang",3 ) This dog object is saved to a file and can be restored from the file.
3. The above requirement is to be able to serialize and deserialize basic data types or objects

Serialization and deserialization

1. Serialization is to save the value and data type of the data when saving the data
2. Deserialization is to restore the value and data type of the data when restoring the data
3. To make an object support the serialization mechanism, you must let Its class is serializable. In order for a class to be serializable, the
class must implement one of the following two interfaces:
Serializable This is a marker interface (usually implements this)
Externalizable

Object Processing Flow Considerations and Details

1)读写顺序要一致(怎么写进去的就按那个顺序去序列化读取)
2)要求序列化或反序列化对象,需要实现Serializable(基本类型会自动装箱(基本类型封装类已经实现了Serializable接口),对象的话需要实现Serializable接口)
3)序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性(private static final long serialVersionUID = 1L;)
4)序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
5)序列化对象时,要求里面属性的类型也需要实现序列化接口
6)序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化

Use Cases:

    @Test
    public void objectInputStream() throws IOException, ClassNotFoundException {
    
    
        String filePath ="e:\\data.txt";
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filePath));
        //读取(反序列化)的顺序需要和你保存数据(序列化)的顺序一致否则会出现异常
        System.out.println(objectInputStream.readInt());
        System.out.println(objectInputStream.readBoolean());
        System.out.println(objectInputStream.readChar());
        System.out.println(objectInputStream.readDouble());
        System.out.println(objectInputStream.readUTF());
        //dog的编译类型是 0bject , dog的运行类型是 Dog
        Object dog = objectInputStream.readObject();
        System.out.println("运行类型="+dog.getClass());
        System.out.println("dog信息=" + dog);
        //这里是特别重要的细节:
        //1.如果我们希望调用Dog的方法,需要向下转型
        //2.需要我们将Dog类的定义,拷贝到可以引用的位置(!!!因为序列化的时候会把具体包名什么都写进去,可以把Dog类做成一个public类)
        Dog dog2 = (Dog) dog;
        System.out.println(dog2.getName());
        objectInputStream.close();
    }
public class Dog implements Serializable {
    
    
    private String name;
    private int age;
    public Dog(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }
    public String getName() {
    
    
        return name;
    }
    public void setName(String name) {
    
    
        this.name = name;
    }
    public int getAge() {
    
    
        return age;
    }
    public void setAge(int age) {
    
    
        this.age = age;
    }
    @Override
    public String toString() {
    
    
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Commonly used subclasses of OutputStream (byte output stream)

1.FileOutputStream:

File input stream, byte-wise
Sample code:

    @Test
    public void fileOutputStream() throws IOException {
    
    
        String path = "e:\\a.txt";
        FileOutputStream fileOutputStream = null;
        try {
    
    
            fileOutputStream = new FileOutputStream(path,true);     //这个构造器后面加个true,表示续写而不是覆盖文件原有内容
            fileOutputStream.write('s');                        	//第一种方式,写入一个字节
            String str = "asdf,sdffff";
            fileOutputStream.write(str.getBytes());                 //第二种方式,把一个字符串装换成字节数组输入      str.getBytes()-->可以把字符串变成字节数组
           // fileOutputStream.write(byte[] b,int 0,int len);       //第三种方式,可以从自定位置输入自定字节数    off表示从下标几,len表示写入前几个字节
            } catch (IOException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            fileOutputStream.close();
        }
    }

Copy of files (ordinary copy)

    @Test
    public void copyfile(){
    
    
        String InputFath =  "f:\\cjy.png";
        String OutputFath = "f:\\cjy2.png";
        FileInputStream   fileInputStream =null;
        FileOutputStream fileOutputStream =null;
        int readLen = 0;                   //存一次读取了几个字节(因为最后一次可能没有读完,或者说没有读到数据会返回-1)
        byte[] data = new byte[2];        //设置一个读取几个字节
        try {
    
    
            fileInputStream = new FileInputStream(InputFath);
            fileOutputStream = new FileOutputStream(OutputFath);
            while((readLen=fileInputStream.read(data))!=-1){
    
    
                fileOutputStream.write(data,0,readLen);
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            try {
    
    
                fileOutputStream.close();
                fileInputStream.close();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
    }

2.BufferedOutputStream:

Use Cases:

    @Test
    public void bufferedOutputStream() throws IOException {
    
    
        String path = "f:\\s.txt";
        BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(path));
        bo.write("这是一个字符串===".getBytes());
        bo.close();                             //这里底层会去实现FileReader.close()方法
    }

3.ObjectOutputStream:

Use Cases:

    @Test
    public void objectOutputStream() throws IOException {
    
    
        String filePath ="e:\\data.txt";     //序列化后,保存的文件格式,不是存文本,而是按照他的格式来保存
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
        oos.writeInt(100);               //int(自动装箱)--> Integer(实现了 Serializable)
        oos.writeBoolean(true);         // boolean -> Boolean(实现了Serializable)
        oos.writeChar( 'a');            //Char --> Character(实现了Serializable)
        oos.writeDouble(9.5);           // double -> Double(实现了Serializable)
        oos.writeUTF("韩顺平教育");     //String -->实现了Serializable
        //保存一个dog对象
        oos.writeObject(new Dog("asd",10));      //对象的类需要实现序列化接口
        oos.close();
        System.out.println("数据保存成功");
    }
public class Dog implements Serializable {
    
    
    private String name;
    private int age;
    public Dog(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }
    public String getName() {
    
    
        return name;
    }
    public void setName(String name) {
    
    
        this.name = name;
    }
    public int getAge() {
    
    
        return age;
    }
    public void setAge(int age) {
    
    
        this.age = age;
    }
    @Override
    public String toString() {
    
    
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Commonly used subclasses of Reader (character input stream)

1.FileReader:

Reads only one character or character array at a time, very inefficient
Use case:

    @Test
    public void fileReader() throws IOException {
    
    
        String path = "f:\\s.txt";
        int readChar = 0;
        char[] buf = new char[8];
        FileReader fileReader = new FileReader(path);
        while ((readChar=fileReader.read(buf))!=-1){
    
    
            System.out.print(new String(buf,0,readChar));
        }
        fileReader.close();
    }

2.BufferedReader:

Use this for text documents and the like, which is very efficient!
Use Cases:

    @Test
    public void bufferedReader() throws IOException {
    
    
        String path = "f:\\s.txt";
        String readLine = null;
        BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
        while ((readLine=bufferedReader.readLine())!=null){
    
         //readLine()是按行读取,读不到的话返回null
            System.out.println(readLine);
        }
        bufferedReader.close();             					//这里底层会去实现FileReader.close()方法
    }

3.InputStreamReader (conversion stream)

Reader subclass

Necessity of conversion stream:

	文件的读取默认是UTF-8编码的,如果读取的文件不是UTF-8编码的,那读取出来的就会是乱码,
	而装换流可以把字节流装换成字符流并设置指定的读取编码(InputStreamReader 构造器自带的)
	其实也相当于给字节流又包装了一层

Use Cases:

    @Test
    public void InputStreamReader() throws IOException {
    
    
        String filePath = "e:\\a.txt";
        //指定gbk(看文件是什么编码的就用什么编码方式)的编码方式把FileInputStream转换成InputStreamReader
        InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");
        BufferedReader     br = new BufferedReader(isr);        //读取还是用缓冲流读取效率高
        String reader = null;
        while ((reader = br.readLine())!=null){
    
    
            System.out.println(reader);
        }
        br.close();
    }

Commonly used subclasses of Writer (character output stream)

1.FileWriter:

Use Cases:

    @Test
    public void fileWriter() throws IOException {
    
    
        String path = "f:\\s.txt";
        char[] chars = {
    
    'a','b','c'};
        FileWriter fw = new FileWriter(path);
        fw.write('d');        //写入一个字符
        fw.write(chars);         //写入一个字符数组
        fw.write("字符串转数组".toCharArray(),0,3);   //写入前三个数据
        fw.write("这是一个案例");     //写入整个字符串
        System.out.println("写入文件成功!");
        fw.close();
    }

2.BufferedWriter:

Use Cases:

    @Test
    public void bufferedWriter() throws IOException {
    
    
        String path = "f:\\s2.txt";
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(path,true));   //追加的话是在节点流有这个属性,BufferedWriter构造器没有这个属性
        String str = "sfsdfSDFDASFsdfasdf收待发放";
        bufferedWriter.write(str);
        bufferedWriter.newLine();           //插入一个换行符号
        bufferedWriter.write(str);
        bufferedWriter.close();             //这里底层会去实现FileReader.close()方法
    }

Copy of files (buffered streaming copy)

This approach is efficient and is often used in this
use case:

    @Test
    public void bufferedCopy() throws IOException {
    
    
        String Readerpath = "f:\\s.txt";
        String Writerpath = "f:\\s2.txt";
        String readLine = null;
        BufferedReader bufferedReader = new BufferedReader(new FileReader(Readerpath));
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(Writerpath));
        while ((readLine=bufferedReader.readLine())!=null){
    
    
            bufferedWriter.write(readLine);
            bufferedWriter.newLine();
        }
        if (bufferedReader!=null){
    
    
            bufferedReader.close(); 
        }
        if (bufferedWriter!=null){
    
    
            bufferedWriter.close();
        }
        bufferedWriter.close();
    }

3.OutputStreamWriter: (conversion stream)

Writer subclass
use cases:

    @Test
    public void outputStreamWriter() throws IOException{
    
    
        String filePath = "e:\\a2.txt";
        String charSet = "utf-8";
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), charSet);
        osw.write("这是一个案例");
        osw.close();
        System.out.println("按照"+charSet+"写入文件成功");
    }

Five. Standard input and output stream

  • System.in standard input stream type: InputStream can input from the keyboard
  • System.out Standard output stream type: OutpuStream Normal console output (default output location)
    use cases:
		Scanner scanner = new Scanner(System.in);     //Scanner会一直等待控制台输入并回车才会执行接下去的程序(获取控制台数据)
		System.out.println("输入内容");
		String next = scanner.next();
		System.out.print1n("next=" +next);

6. Print flow

Print stream has only input stream and no output stream

  • PrintStream (byte stream): OutputStream subclass
    Use cases:
    @Test
    public void printStream() throws IOException {
    
    
        PrintStream out = System.out;       //System.out是OutpuStream类型的输出流
        //普通方式打印
        out.print("demo===");
        out.write("demo2".getBytes());     //因为print底层使用的是write ,所以我们可以直接调用write进行打印/输出,默认输出位置是控制台
        out.close();
        //我们可以去修改打印流输出的位置/设备//1.输出修改成到“e:\\f1.txt"
        System.setOut(new PrintStream("e:\\fi.txt"));
        System.out.println("hello,韩顺平教育");              //这样这个打印的位置就不再是控制台而是e:\\f1.txt里了
    }
  • PrintWriter (character stream): Writer subclass
    Use cases:
    @Test
    public void printWriter() throws IOException {
    
    
        PrintWriter printWriter = new PrintWriter(System.out);        //控制台输出
        PrintWriter printWriter2 = new PrintWriter(new FileWriter("e:\\f2.txt"));  //重定向输出位置到某个文件
        printWriter.print("哈哈");            //控制台输出
        printWriter2.print("哈哈2");          //指定文件输出
        printWriter.close();
        printWriter2.close();
    }

7. Personal summary

The usage of streams is similar, the main thing is to know when to use which stream is appropriate! In addition, the stream must be closed after the data is read. If the stream is processed, the outer stream can be closed. If the stream is not closed, the resource consumption will be relatively large.

learning address

Guess you like

Origin blog.csdn.net/cc1373709409/article/details/123049927