Java IO流从入门到精通————学习笔记

IO入门笔记

推荐视频学习连接
(间断更新,QVQ学业繁重,课上用到IO流的次数太少了,我们老师5分钟给我们讲完,学习视频8个小时T_T,但愿我的笔记对你有用)

一、IO流概念

1.1基础知识

在Java程序中,对于数据的输入(input)/输出(output)操作以"流”(stream) 方式进行; Java提供了各种各样的“流"类,用以获取不同种类的数据;程序中通过标准的方法输入或输出数据。
Java的流类型-般位于java.io包中。
数据源data source ,提供原始数据的原始媒介。常见的:数据库、文件、其他程序、内存、网络连接、IO 设备。

流是一个抽象、动态的概念,是一连串连续动态的数据集合。

Java IO流从入门到精通————学习笔记_第1张图片


1.2流的分类

按流的方向分类:

​ 输出流:数据流向是数据源到程序(以InputSream、Reader结尾的流)

​ 输出流:数据流向是程序到目的地(以Outputstream、Writer结尾的流)

(注:输入输出流的划分是相对程序而言的,并不是相对数据源)


按处理的数据单元分类:

​ 字节流:以字节为单位获取数据,命名以Stream结尾的流一般是字节流,顶级类是InputStream、OutStream

​ 字符流:以字符为单位获取数据,命名以Reader/Writer结尾的流一般是字符流,顶级类Reader、Writer。

**按处理对象不同分类:**

​ 节点流:可以直接从数据源或目的地读写数据,如FileinputStream、FileReader等。

​ 处理流:不直接连接到数据源和目的地,是“处理流的流”。通过对其他流的处理提高程序的性能如,BufferedInputStream、BufferedReader等。处理流也叫包装流。

​ (注:节点流处于IO操作的第一线,所有操作必须通过它们进行;处理流可以对节点流进行包装,提高性能或程序的灵活性)

(数据流是必不可少,处理流只是包装,能提高性能,但可以没有)

1.3 IO流体系结构

字节流

(1)inputStream和OutStream是java语言中最基本的两个输入输出类,其他所有字节输入输出流都继承自这两个基类

(2)这两类都是抽象类,不能创建他们的实例,自能使用他们的子类

(3)FilerInputStream和FilerOutputStream是所有包装流的父类

字符流

(1)java语言中最基本的两个字符输入输出类,Reader和Writer

(2)其他所有字符输入输出类都继承自这两个基类。

(3)这两个都是抽象类,不能创建他们的实例,只能用他们的子类

1.4File类的使用

File类用来代表文件和文件夹。主要作用有两个:获取文件夹的属性;实现对文件、文件夹的创建和删除。文件夹:file folder 目录:directory

常用的方法:

import java.io.File;
import java.util.Date;

public class Demo02File {
    public static void main(String[] args) {
        File file = new File("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档.txt");//绝对路径,根路径
        System.out.println(file.getName());//返回文件名
        System.out.println(file.length());//字节长度
        System.out.println(file.exists());//是否存在

        System.out.println(file.canRead());//是否可读
        System.out.println(file.canWrite());//是否可写
        System.out.println(file.canExecute());//是否可执行

        System.out.println(file.isFile());//是文件吗
        System.out.println(file.isDirectory());//是目录(文件夹)吗

        File file1 = new File("D:\\steam");//打开一个文件夹
        File[] files = file1.listFiles();
        System.out.println(files.length);//返回steam文件夹中文件和文件夹的数量和
        for (File i : files) {
            //获得steam文件夹中文件和为文件夹的名称和最后修改时间
            System.out.println(i.getName()+"\t"+new Date(i.lastModified()).toLocaleString());
        }
    }
}

创建、删除文件夹

import java.io.File;
import java.io.IOException;

public class Demo02NewFile {
    public static void main(String[] args) throws IOException {
        //创建一个File对象指向一个文件
        File file = new File("D://first.txt");
        //如果这个文件夹存在,删除;不存在,创建。
        if(file.exists()){
            file.delete();
        }else{
            file.createNewFile();
        }
    }
}

但是File不能对文件的内容进行 操作,内容操作要使用IO流

二、文件流

2.1文件字节流 FileOutputStream 和FileInputStream

(1)FileOutputStream 和FileInputStream是字节流,是节点流,数据源和目的地是文件夹。

(2)复制文件需要分别创建一个输入输出流完成文件读写

(3)需要创建一个中转站,借助循环和中转站完成复制

(4)使用完毕一定要关闭,这和垃圾回收没用关系(一定要关闭QVQ,我在第二次使用这个方法输入14M的音乐文件,输出了1.3G,而且输出的文件打开了把我电脑弄死机了)

复制一个txt文档

import java.io.*;

public class Demo03Copy {
    public static void main(String[] args) throws IOException {
        //1.创建输入流和输出流
        File file1 = new File("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档.txt");
        File file2 = new File("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档1.txt");
        FileInputStream is = new FileInputStream(file1);
        FileOutputStream os = new FileOutputStream(file2,true);//append    true追加(追加是指到指定的文件中)   false 覆盖(把指定的文件完全覆盖掉)
        //2.使用输入流和输出流完成文件复制
        int n;//定义一个中转站,就是一个字节
        n = is.read();
        while(n != -1){ //n == -1 读到了文件末尾
            //写一个字节
            os.write(n);
            n = is.read();
        }
        //3.完毕关闭输入、输出流
        is.close();
        os.close();

    }
}

缺点:中转站太小,速度慢,效率低;复制更大文件时效果更明显;可以将中转站由一个字节变成一个字节数组,减少读写硬盘的次数。

复制一个MP4文件(一定要关闭IO流)


import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo04CopyBigFile {
    public static void main(String[] args) throws IOException {
        FileInputStream is = new FileInputStream("C:\\Users\\帅气的影山瑞\\Desktop\\東山奈央 - 月がきれい.mp3");
        FileOutputStream os = new FileOutputStream("C:\\Users\\帅气的影山瑞\\Desktop\\東山奈央 - 月がきれい1.mp3",true);

        byte[] bytes = new byte[1024];//定义一个字节数组,是一个中转站
        int len = is.read(bytes);//读文件的内容放到字节数组中,返回读取的字节数
        while(len != -1){
            os.write(bytes,0,len);
            len = is.read(bytes);
        }
        //完毕关闭输入输出流
        os.close();
        is.close();
    }
}

异常处理

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo05FileException {
    public static void main(String[] args) {
        FileInputStream is = null;
        FileOutputStream os = null;
        try {
            is = new FileInputStream("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档.txt");
            os = new FileOutputStream("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档1.txt",true);
            int len;
            len = is.read();
            while(len != -1){
                os.write(len);
                len = is.read();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                if(is != null){
                    is.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

分析:创建流、使用流要使用一次try-catch语句,关闭流要分开进行异常处理

Java7异常处理新特性:try-with-resource:不用显示的进行资源的关闭,子要将资源的实例化对象放入try后面的()中,作用范围是当前的try语句,执行完毕后会自动进行关闭,可省略finally语句,更加简单实用

关于java9中异常处理新变化:try之前定义好对象,try()括号中引入创建好的对象。如果多个对象,使用;分割。如果try之前的定义的对象对抛出异常,就不推荐使用该方式,因为需要在方法签名中throws异常

2.2文件字符流

字符流复制txt文件

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Demo06charFile {
    public static void main(String[] args) throws IOException {
        //1.创建输入流和输出流
        FileReader fr = new FileReader("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档.txt");
        FileWriter fw = new FileWriter("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档1.txt");
        //2.1使用输入流和输出流复制文件
        int n;//定义中转站
        n =fr.read();
        while(n != -1){
            fw.write(n);
            System.out.println((char) n);
            n = fr.read();
        }
//        3.关闭输入流和输出流
        fr.close();
        fw.close();
    }
}

字符流复制大文件

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Demo07CharBigFilr {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档.txt");
        FileWriter fw = new FileWriter("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档1.txt");

        char[] cbuf = new char[1024];//定义中转站,一个字符数组
        int len = fr.read(cbuf);
        while(len != -1){
            //写一个字符数组的内容到文件
            fw.write(cbuf,0,len);
            //输出到控制台
            System.out.println(len);
            System.out.println(cbuf);
            len = fr.read(cbuf);
        }
        fr.close();
        fw.close();
    }
}

2.3总结

(1)使用字节流可以读写任意类型的文件

(2)使用字符流只可以读写文本文件(使用记事本可以打开的文件) #doc文件不是文本文件

(3)使用字符流的好处;处理非英文字符(汉字之类)方便

(4)其实只有字节流,没有字符流;字符流的底层还是字节流

三、缓冲流

(1)使用缓冲流可以提高读写速度

(2)关闭高层流即可,无需关闭底层流(关闭高层流其实就是再关闭底层流)

(3)缓冲流为什么可以提高查询的速度(因为输入输出缓冲区,大大减少了读写硬盘的次数)

(4)如何刷新输出缓冲区(将缓冲区的最新数据写入到文件中)

​ 方法一:bos.close(); 先刷新,再关闭。

​ 方法二:直接调用 bos.flush();

​ 方法三:缓冲区满,自动刷新

Java IO流从入门到精通————学习笔记_第2张图片

import java.io.*;

public class Demo08Buffered {
    public static void main(String[] args) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档.txt"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\帅气的影山瑞\\Desktop\\新建文本文档1.txt"));
        byte[] bytes = new byte[1024];
        int len =bis.read(bytes);
        while(len != -1){
            bos.write(bytes,0,len);
            System.out.println(len);
            len = bis.read();
        }
        bis.close();
        bos.close();
    }
}                      

四、数据流和对象流

​ 之前使用文件流、缓冲流读取文件只能按照字节、数组方式读取,最方便的也是按行读取,能否很方便的实现对各种基本类型和引用类型数据的读写,并保留其本身的类型。数据流DataInputStream和DataOutputStream和对象流ObjectInputStream和ObjectOutputStream可以解决这个问题,最大的优势就是提供了方便操作各种数据类型的方法,直接调用,简单方便。

注意
●只有字节流,没有字符流
●都是处理流,不是节点流
●数据流只能操作基本数据类型和字符串,对象流还可以操作对象
●写入的是二进制数据,无法直接通过记事本等查看
●写入的数据需要使用对应的输入流来读取

4.1数据流 DataInputStream和DateOutputStream

//数据流最大的优点就是方便
public class Demo09DataStream {
    public static void main(String[] args) {
        try {
            read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void read() throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\帅气的影山瑞\\Desktop\\io.txt"));
        DataInputStream dis = new DataInputStream(bis);
        System.out.println(dis.readInt());
        System.out.println(dis.readChar());
        System.out.println(dis.readDouble());
        System.out.println(dis.readBoolean());
    }
    public static void write() throws IOException {
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\帅气的影山瑞\\Desktop\\io.txt"));
        DataOutputStream dos = new DataOutputStream(bos);
        dos.writeInt(33);
        dos.writeChar('d');
        dos.writeDouble(1.35);
        dos.writeBoolean(false);
        dos.close();

    }
}

4.2对象流 ObjectInputStream和ObjectOutputStream

import java.io.*;
import java.util.Date;

public class Demo10ObjectStream {
    public static void main(String[] args) {
        try {
//            write();
            read();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
    public static void read() throws IOException, ClassNotFoundException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\帅气的影山瑞\\Desktop\\io.txt"));
        ObjectInputStream ois = new ObjectInputStream(bis);
        System.out.println(ois.readInt());
        System.out.println(ois.readChar());
        System.out.println(ois.readDouble());
        Date o = (Date)ois.readObject();
        System.out.println(o);
        ois.close();
    }
    public static void write() throws IOException {
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\帅气的影山瑞\\Desktop\\io.txt"));
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeInt(3424);
        oos.writeChar('3');
        oos.writeDouble(3.22);
        oos.writeObject(new Date());
        oos.close();
    }
}

注意:使用对象流读写引用类型的数据,需要相应类实现Serializable接口,否则会提示异
常提、没有序列化,比如:java.io.NotSerializableException: com.bjsxt.entity .Student。

4.3序列化和反序列化

1.什么是序列化和反序列化?

序列化: Serialization 将对象的状态信息转换为可以存储或传输的形式的过程。
对象(内存------>字节数组字节序列(外存、网络)

反序列化: DeSerialization
字节数组字节序列(外存、网络) -------->对象(内存)

2.什么时候需要序列化和反序列化?

存储或传输比如存储到外存(硬盘)中传输到网络

你可能感兴趣的:(java)