• JavaSE之IO流加强


    IO流异常的处理

    JDK1.7的处理方式

    JDK7增加 try-with-resource 语句来处理资源,该语句确保了每个资源在语句结束时关闭。

    /*
        JDK7以前的处理IO流异常
            try {
                可能有问题的代码
            } catch (异常类名 变量名) {
                处理异常的代码
            } finally {
                关闭流
            }
    
            代码繁琐
    
        JDK7处理IO流异常
            会自动关闭流
    
            try (创建流的代码) {
                可能有问题的代码
            } catch (异常类名 变量名) {
                处理异常的代码
            }
    
     */
    public class Demo01 {
        public static void main(String[] args) {
            // JDK1.7以前处理IO流异常
            FileReader fir = null;
            try {
                fir = new FileReader("study_day11\\abc\\1.txt");
                fir.read();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    //fir可能获取失败,所以先进行判断
                    if(fir != null){
                        fir.close();
                    }
    
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            // JDK1.7处理IO流异常, 只有实现了AutoCloseable接口的类才能放入,会自动关闭流
            try(
                    //自动关闭流,两个以上用分号隔开
                    FileReader fir1 = new FileReader("study_day11\\abc\\1.txt");
                    FileWriter fiw = new FileWriter("study_day11\\abc\\1.txt")
            ){
                fir.read();
                fiw.write("1");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    缓冲流

    基本流

    字节流: FileInputStream , FileOutputStream

    字符流: FileReader , FileWriter

    缓冲流,转换流,对象流等是对基本流的增强。

    缓冲流是对4个基本的 FileXxx 流的增强,所以也是4个流,按照数据类型分类:

    字节缓冲流: BufferedInputStream , BufferedOutputStream

    字符缓冲流: BufferedReader , BufferedWriter

    缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

    字节缓冲流

    /*
    目标:字节缓冲流(重点)
    讲解:
         基本流:
                            输入流                 输出流
            字节流         FileInputStream         FileOutputStream
            字符流         FileReader              FileWriter
    
        我们知道在操作流的时候使用不带数组读取的次数很多,效率低.带数组,提高效率.
        既然带数组可以提高效率,Java自己写好了4个类,带数组,提高效率.
        这些带数组的流称为缓冲流(高效流), 内部的数组称为缓冲区
    
        缓冲流:
                            输入缓冲流              输出缓冲流
            字节流     BufferedInputStream     BufferedOutputStream
            字符流     BufferedReader          BufferedWriter
    
        缓冲流的规律:
            1.以Buffered开头
            2.后缀就是继承的父类
    
    
    目标:学习字节缓冲流
    
        字节输出缓冲流
        字节输入缓冲流
    
        字节输出缓冲流
            构造方法:
                BufferedOutputStream(OutputStream out)
    
            普通方法:
                还是OutputStream父类的那些write方法
    
        字节输入缓冲流
            构造方法:
                BufferedInputStream(InputStream in)
    
            普通方法:
                还是InputStream父类的那些read方法
    */
    public class Demo02 {
        public static void main(String[] args) throws Exception {
                fun1();
                fun2();
        }
    
        /*
            BufferedOutputStream:
                构造方法:
                    BufferedOutputStream(OutputStream out) 真正操作文件传入的流, 他内部有一个8192大小的数组,提高效率的
         */
    
        public static void fun1() throws IOException {
            //1.基本写字节流
            FileOutputStream stream = new FileOutputStream("study_day11//abc//1.txt");
    
            //2.创建缓冲流
            BufferedOutputStream bos = new BufferedOutputStream(stream);
            //3.写操作
            bos.write(97);
            //4.关闭流,将基本流放在try()中,因为实现了AutoCloseable接口,会自动帮我们关闭基本流
            bos.close();
            //stream.close()
        }
    
        /*
            BufferedInputStream:
                构造方法:
                    BufferedInputStream(InputStream in) 真正操作文件靠传入的流, 缓冲流内部提供8192大小的数组,提高效率
         */
        public static void fun2() throws Exception {
            //1.基本读字节流
            FileInputStream inputStream = new FileInputStream("study_day11//abc//1.txt");
            //2.创建缓冲流
            BufferedInputStream bis = new BufferedInputStream(inputStream);
            //3.读操作
            int read = bis.read();
            System.out.println((char)read);
            //4.关闭流
            bis.close();//底层会帮我们关闭基本流,调用基本流.close()
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    缓冲流读取一个字节比基本流读取一个字节快非常多

    缓冲流读取一个字节数组和基本流读取一个字节数组差不多

    字节流使用时建议使用基本流+数组

    字符缓冲流及特有方法

    /*
    目标:字符缓冲流及特有方法(重点)
    
    讲解:
        字符输出缓冲流
        字符输入缓冲流
    
    小结:
        1.BufferReader特有方法?
            readLine() // 读一行, 读取到\r\n结束
    
        2.BufferedWriter特有方法?
            newLine() 换行, 相当于write("\r\n");
     */
    public class Demo04 {
        public static void main(String[] args) throws Exception {
            fun1();
            fun2();
        }
    
        /*
            BufferedWriter:
                构造方法:
                    BufferedWriter(Writer out) 真正靠参数传入的流去操作文件, 内部有一个8192大小的数组,提高效率
                特有方法:
                    void newLine():
         */
        public static void fun1() throws Exception {
            BufferedWriter bfw = new BufferedWriter(new FileWriter("study_day11//abc//1.txt"));
            bfw.write("今天星期一");
            //换行
            bfw.newLine();
            bfw.write("不吃肯德基");
            //如果忘记关闭流,还会导致原本文件中的数据丢失
            //底层将基本流放在try()中,因为实现了AutoCloseable接口,会自动帮我们关闭基本流
            bfw.close();
        }
    
    
        /*
            BufferedReader:
                构造方法:
                    BufferedReader(Reader in) 真正操作文件靠参数传入的流, 提供8192大小的数组,提高效率
                特有方法:
                    String readLine()
         */
    
        public static void fun2() throws Exception {
            BufferedReader bfr = new BufferedReader(new FileReader("study_day11//abc//1.txt"));
            /*//只能读一个
            int read = bfr.read();
            System.out.println((char)read);*/
    
            /*//读一行
            String s = bfr.readLine();
            System.out.println(s);*/
    
            //循环
            String i;
            while((i = bfr.readLine())!=null){
                System.out.println(i);
            }
            底层会帮我们关闭基本流,调用基本流.close()
            bfr.close();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    字符集是一些字符的集合。

    ASCII字符集
    ISO-8859-1字符集
    GBxxx字符集
    Unicode字符集

    字符编码是字符与数字之间的对应规则。

    将字符转成二进制,称为编码。

    使用ASCII编码,将 ‘b’ -> 01100010

    将二进制数解析成文字,称为解码。

    使用ASCII编码,将 01100010 -> ‘b’

    转换流

    InputStreamReader

    OutputStreamWriter

    /*
    目标:学习字符流读不同编码的文件乱码问题
    
    讲解:
        中文在GBK编码中占2个字节
        中文在UTF-8编码中占3个字节
    
        IDEA默认是UTF-8编码
    
    小结:
        1.为什么会乱码?
            保存和读取使用了不同的编码
    
        2.如何解决乱码?
            保证读取时的编码和保存的编码是相同的就可以
     */
    public class Demo06 {
        public static void main(String[] args) throws Exception {
            fun1();
        }
    
        // 字符流读取UTF-8的文字 (正常) IDEA默认是UTF-8编码,文件也是UTF-8编码
        //UTF-8大小写都行,-也可以省略
        public static void fun1() throws Exception {
            InputStreamReader ir = new InputStreamReader(new FileInputStream("study_day11\\abc\\student.txt"), "utf8");
            //默认是utf8,可以指定
            int len;
            while ((len = ir.read()) != -1) {
                System.out.println((char) len);
            }
            ir.close();
        }
    
        // 字符流读取GBK的文字 (有乱码, 文件是GBK编码, IDEA读取时默认使用UTF-8读取)
        public static void fun2() throws Exception {
            OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream("\"study_day11\\\\abc\\\\student.txt\""), "GBK");
    
            os.write("我爱你");
            os.close();
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    /*
    转换流,指定编码读取/写数据
    
    目标:学习InputStreamReader转换流读取字符数据
    
    讲解:
        InputStreamReader类的说明:
            继承了Reader属于字符流体系,使用父类Reader中的read方法来读取数据,可以指定编码来读取数据
    
        构造方法:
            InputStreamReader(InputStream in) 创建InputStreamReader,使用默认的字符集操作字符(IDEA默认UTF-8)
            InputStreamReader(InputStream in, String charsetName) 创建InputStreamReader,使用指定字符集操作字符
                String charsetName: 通常写GBK/UTF-8 大小写都行
    
        InputStreamReader类的好处
            可以指定编码读取数据
     */
    public class Demo07 {
        public static void main(String[] args) throws Exception {
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("study_day11//abc/2.txt"));
            InputStreamReader isr = new InputStreamReader(new FileInputStream("study_day11//abc/2.txt"));
            osw.write("a");
            isr.read();
            isr.close();
            osw.close();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    /*
    目标:学习OutputStreamWriter转换流写字符数据
    
    讲解:
        类的说明:
            OutputStreamWriter 继承了Writer,属于字符流体系,还是使用Writer父类的那些write方法写数据.可以指定字符集
    
        构造方法:
            OutputStreamWriter(OutputStream out) 创建一个OutputStreamWriter, 使用默认编码写数据(IDEA默认编码是UTF-8)
            OutputStreamWriter(OutputStream out, String charsetName) 创建一个OutputStreamWriter, 使用指定编码写数据
    
    
        OutputStreamWriter类的好处
            可以指定编码写字符数据
     */
    public class Demo08 {
        public static void main(String[] args) throws Exception {
            // 写数据到GBK编码的文件
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(""),"GBK");
            osw.write(97);
            osw.close();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    对象流

    ObjectOutputStream

    /*
    目标:学习对象输出流将对象写到文件中
    
    ObjectOutputStream (对象输出流/序列化流)
        将对象的数据保存到文件
    
        构造方法:
            ObjectOutputStream(OutputStream out) 创建ObjectOutputStream对象,将对象数据写入指定文件
    
        特有方法:
            void writeObject(Object obj)
    
    注意:
        1.对象要序列化到文件,这个类要实现Serializable接口
            Serializable标记接口. 主要给JVM虚拟机看的.看到Serializable接口会把对象转成字节数据.我们就可以通过流写到文件中
    
        2.被transient修饰的成员变量不会保存到文件
    
        3.InvalidClassException: 无效的类异常,就是版本号对不上了
            出现的步骤:
                1.执行 writeObject 把对象保存到文件
                2.修改 Person 类
                3.执行 readObject 读取文件的对象
    
                在String类中找到版本号的编写方式,版本号本身可以随意修改
    
     */
    public class Demo10 {
        public static void main(String[] args) throws Exception {
            // ObjectOutputStream: 包装加强.把对象保存到文件
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("study_day11/abc/3.txt"));
            Person person = new Person("张三", 18);
            oos.writeObject(person);
            //关闭流
            oos.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    Person

    public class Person implements Serializable{
        private String name;
        private int age;
        //版本号
        private static final long serialVersionUID = -3894758923477710L;
    
        public Person() {
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        /**
         * 获取
         * @return name
         */
        public String getName() {
            return name;
        }
    
        /**
         * 设置
         * @param name
         */
        public void setName(String name) {
            this.name = name;
        }
    
        /**
         * 获取
         * @return age
         */
        public int getAge() {
            return age;
        }
    
        /**
         * 设置
         * @param age
         */
        public void setAge(int age) {
            this.age = age;
        }
    
        public String toString() {
            return "Person{name = " + name + ", age = " + age + "}";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    ObjectInputStream

    /*
    目标:学习对象输入流将文件中的对象读入程序中
    
    讲解:
        ObjectInputStream类 对象输入流,读取文件中的数据到程序中形成对象
    
        构造方法:
            ObjectInputStream(InputStream in) 创建ObjectInputStream对象,通过基本流指定读取哪个文件
    
        特有方法:
            Object readObject()
     */
    public class Demo11 {
        public static void main(String[] args) throws Exception {
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("study_day11//abc//3.txt"));
            Object o = ois.readObject();
            System.out.println(o);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?

    给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程

    打印流

    /*
    目标:学习打印流
    
    讲解:
        打印流分类: Print
            字节打印流: PrintStream      *
            字符打印流: PrintWriter
    
        PrintStream类的使用:
            构造方法:
                PrintStream(String fileName) 创建PrintStream, 指定打印的目的地
                PrintStream(File file) 创建PrintStream, 指定打印的目的地
                PrintStream(OutputStream out) 创建PrintStream, 指定打印的目的地
    
            普通方法:
                print(Xxx x) 打印数据,不换行
                println(Xxx x) 打印数据,换行
                原样输出,参数写什么就打印什么
    
    小结:
        2.PrintStream类常用哪2个方法?
            print(Xxx x) 打印数据,不换行
            println(Xxx x) 打印数据,换行
    
    alt + 鼠标左键拖动: 多行编辑
    
        将来我们学习Java做网站,就是使用打印流把数据打印到浏览器上面
     */
    public class Demo13 {
        public static void main(String[] args) throws Exception {
            // 创建打印流
            PrintStream printStream = new PrintStream(new FileOutputStream("study_day11//abc//1.txt"));
            printStream.println(true);
    
            printStream.close();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    Properties

    /*
    目标:学习Properties作为集合的使用
    
    讲解:
        继承体系
           Map
            ↑   实现
        Hashtable
            ↑   继承
        Properties
    
    
        Properties类介绍:
            1.Properties实现了Map接口,就是一个双列集合可以存储键值对数据, 键和值都是字符串类型
            2.Properties可以结合流进行操作, 可以把集合中的数据保存到流中, 也可以从流中来加载数据
    
        Properties作Map集合的特有方法:
            Object setProperty(String key, String value) 添加键值对,修改键值对
            String getProperty(String key) 通过键获取值
    
    小结:
        Properties是一个Map集合,可以存储键值对数据,键和值都是String类型
    
     */
    public class Demo141 {
        public static void main(String[] args) {
            // Properties作为Map集合的使用
            Properties properties = new Properties();
            properties.setProperty("年龄","18");
            properties.setProperty("姓名","张");
            String name = properties.getProperty("姓名");
            String age = properties.getProperty("年龄");
            System.out.println(name+age);
    
            properties.forEach((k,v)->{
                System.out.println(k+":"+v);
            });
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    Properties和流操作

    /*
    目标:学习Properties保存和加载文件数据
    
    讲解:
        Properties和流操作的特有方法:
            void store(Writer writer, String comments) 把Properties集合中的键值对数据保存到流中
            // Writer writer: 指定数据流向哪个文件
            // String comments: 注释
    
            void load(Reader reader) 把文件的键值对数据加载到Properties集合中
     */
    public class Demo142 {
        public static void main(String[] args) throws Exception {
            //fun1();
            fun2();
        }
    
        // Properties属性集保存数据到文件: void store(Writer writer, String comments)
        public static void fun1() throws Exception {
            Properties properties = new Properties();
            properties.setProperty("username","张三");
            properties.setProperty("password","123456");
            //直接把数据写入文件,不会留在缓冲区
            FileWriter fw = new FileWriter("study_day11//abc/5.txt");
            properties.store(fw,"");
            fw.close();
        }
    
        // 加载文件中数据到Properties属性集中: void load(Reader reader)
        public static void fun2() throws Exception {
            Properties properties = new Properties();
            System.out.println("propreties:"+properties);
            FileReader ifr = new FileReader("study_day11//abc/5.txt");
            properties.load(ifr);
            System.out.println(properties);
            ifr.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    最后

    如果你对本文有疑问,你可以在文章下方对我留言,敬请指正,对于每个留言我都会认真查看。

  • 相关阅读:
    26-网络通信
    Mybatisplus真实高效批量插入附容错机制
    论文学习——降雨场次划分方法对降雨控制率的影响分析
    【Java每日一题】— —第二十二题:类名作参数进行方法调用的传递问题。(2023.10.06)
    搜索——flood fill
    Pandas知识点-详解聚合函数agg
    java面试题
    Torch 数据集放到网络训练(六)
    十一、Filter&Listener
    spdk(一)----为什么要使用spdk?
  • 原文地址:https://blog.csdn.net/weixin_47543906/article/details/127841311