• java IO流进阶操作


    1.处理流(包装流)

    节点流是底层流/低级流,直接和数据源相连

    而处理流(包装流)包装节点流,即可以消除不用节点流的实现差异,也可以提供更方便的方法来完成输入输出操作

    可以认为,包装流是节点流的升级版本!💫

    包装流的两个优点:

    • 性能的提高:增加缓冲的方式来提高输入输出的效率
    • 操作的便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便

    2.BufferedReader

    BufferedReader常用于读取文本文件

    使用示例:

    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    
    /**
     * 包装流
     * BufferedReader常用于读取文本文件
     * 包装流是节点流的升级版本
     */
    public class BufferedReaderTest {
        public static void main(String[] args) throws IOException {
            String filePath = "D:\\hacker.txt";
            BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
            String line;
            // 按行读取,效率高
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
            // 关闭流
            bufferedReader.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    3.BufferedWriter

    很简单,代码示例:

    /**
     * BufferedWriter演示
     */
    public class BufferedWriterTest {
        public static void main(String[] args) throws IOException {
            String filePath = "D:\\hacker.txt";
            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath, true));
            bufferedWriter.write("大河");
            // 插入换行符
            bufferedWriter.newLine();
            bufferedWriter.write("之犬");
            bufferedWriter.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.Buffered字节处理流

    程序示例:

    拷贝图片

    import java.io.*;
    
    /**
     * Buffered字节处理流
     * 拷贝图片
     */
    public class BufferedByteText {
        public static void main(String[] args) throws IOException {
            String srcFilePath = "D:\\xiao.jpg";
            String destFilePath = "D:\\cheng.jpg";
            BufferedInputStream bis = null;
            BufferedOutputStream bos = null;
            try {
                bis = new BufferedInputStream(new FileInputStream(srcFilePath));
                bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
                byte[] buff = new byte[1024];
                int readLen = 0;
                // 循环读文件
                while ((readLen = bis.read(buff)) != -1) {
                    // 边读边写
                    bos.write(buff, 0, readLen);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                assert bis != null;
                bis.close();
                assert bos != null;
                bos.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

    5.对象处理流

    Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。

    将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象。

    整个过程都是 Java 虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象。

    ObjectInputStreamObjectOutputStream 是高层次的数据流,它们包含反序列化和序列化对象的方法。

    简单来说就是,序列化和反序列化:

    • 序列化:保存值和数据类型
    • 反序列化:恢复保存的值和数据类型

    需要让某个对象支持序列化机制,需要保证该类是可序列化的:

    该类必须实现以下两个接口之一:

    • Serializable(优先选择)
    • Externalizable

    序列化演示:

    /**
     * ObjectOutputStream进行序列化
     */
    @Test
    public void Out() throws IOException {
        String filePath = "D:\\data.dat";
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
        oos.write(100);
        oos.writeBoolean(true);
        oos.writeChar('a');
        oos.writeDouble(5.21);
        oos.writeUTF("IMUSTCTF");
        oos.writeObject(new Dog("旺财"));
        oos.close();
        System.out.println("数据序列化成功!");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    反序列化演示:

    dog类:

    // Dog 需要实现Serializable接口才可以支持序列化操作
    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 +
                    '}';
        }
    }
    
    • 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

    反序列化类:

    /**
     * ObjectInputStream反序列化
     */
    @Test
    public void Input() throws IOException, ClassNotFoundException {
        String filePath = "D:\\data.dat";
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
        // 开始读取bat文件
        // 注意:读取顺序要和序列化时的顺序一致!
        System.out.println(ois.readInt());
        System.out.println(ois.readBoolean());
        System.out.println(ois.readChar());
        System.out.println(ois.readDouble());
        System.out.println(ois.readUTF());
        Object dog = ois.readObject();
        System.out.println(dog);
        // 访问dog的私有属性
        Dog dog1 = (Dog) dog;
        System.out.println(dog1.getName());
        // 关闭外层流
        ois.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    对象处理流使用细节:🎈

    • 序列化的类要实现Serializable接口
    • 请按照序列化的顺序进行反序列化
    • 序列化的类中建议添加如下语句:(为了提高版本的兼容性)
    @Serial
    private static final long serialVersionUID = 1L;
    
    • 1
    • 2
    • 序列化对象时,statictransient修饰的成员不会被序列化
    • 序列化对象时,要求里面的属性也要实现序列化接口💫
    • 序列化具有可继承性,父类实现了序列化,则其子类也会默认实现序列化🚲

    6.转换流

    InputStreamReader可以将InputStream字节流转换成Reader字符流

    /**
     * InputStreamReader演示
     */
    @Test
    public void InputStreamReaderTest() throws IOException {
        String filePath = "D:\\hacker.txt";
        // FileInputStream转换为InputStreamReader
        InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), StandardCharsets.UTF_8);
        // 把InputStreamReader传入BufferedReader
        BufferedReader br = new BufferedReader(isr);
        String s = br.readLine();
        System.out.println(s);
        br.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    OutputStreamWriter可以将OutputStream字节流转换成Writer字符流

    /**
     * OutputStreamWriter
     */
    @Test
    public void OutputStreamWriterTest() throws IOException {
        String filePath = "D:\\hacker.txt";
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), "gbk");
        osw.write("hi,kiki!");
        osw.write("我是大河!");
        osw.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    7.打印流

    PrintStream是字节打印流,代码演示:

    /**
     * 字节打印流
     */
    @Test
    public void PrintStreamTest() throws IOException {
        PrintStream out = System.out;
        // 默认情况下,PrintStream输出的位置是标准输出,即显示器
        out.println("hello!");
        out.write("你好哦".getBytes());
        // 可以修改打印流输出的位置
        // 比如修改打印位置为文件中
        System.setOut(new PrintStream("D:\\hacker.txt"));
        System.out.println("华仔华仔!");
        out.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    PrintWriter是字符打印流,代码演示:

    /**
     * 字符打印流
     */
    @Test
    public void PrintWriterTest() throws IOException {
        PrintWriter printWriter = new PrintWriter(System.out);
        printWriter.println("你好");
        // 可以修改打印流输出的位置
        // 比如修改打印位置为文件中
        PrintWriter pw = new PrintWriter(new FileWriter("D:\\hacker.txt"));
        pw.print("我在文件里");
        printWriter.close();
        pw.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    8.配置文件Properties

    对于一些不经常改变的配置数据,我们可以采用Properties文件进行保存,如保存数据库的连接信息:

    请注意:配置文件的格式(键值对)

    键值对之间不能有空格,值不需要使用双引号包裹!💫

    ip=192.168.0.1
    user=root
    password=youarealoser
    
    • 1
    • 2
    • 3

    采用Properties类读文件

    /**
     * 读取
     */
    @Test
    public void read() throws IOException {
        Properties properties = new Properties();
        // 加载配置文件
        properties.load(new FileReader("io\\mysql.properties"));
        // 把 k-v 显示在控制台
        properties.list(System.out);
        // 根据key获取值
        String password = properties.getProperty("password");
        System.out.println(password);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    采用Properties类修改文件

    /**
     * 修改
     */
    @Test
    public void write() throws IOException {
        Properties properties = new Properties();
        // 设置键值对
        // 如果键已经存在,则等价于修改键
        properties.setProperty("user","汤姆");
        properties.setProperty("passwd","youwillwin");
        // 存储键值对
        properties.store(new FileOutputStream("io\\mysql.properties"),"mysql test data");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    修改后的配置文件内容:

    #mysql test data
    #Fri Aug 05 16:53:29 CST 2022
    passwd=youwillwin
    user=\u6C64\u59C6
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    Android VSYNC发展历程
    STM32(15)USART编程
    测试面试 | 某互联网大厂测试面试真题,你能回答出多少?
    计算机网络(七) | 应用层:HTTPS协议
    Spring 对 Java EE API 整合-5
    [java]深度剖析面向对象编程
    JavaEE 第8节 单例模式详解
    正则表达式中扩展表示法的理解
    内网环境下通过tar包在Linux环境下安装MySQL
    智慧工地平台源码 劳务实名制、视频监控、扬尘监测、起重机械安全监测
  • 原文地址:https://blog.csdn.net/Gherbirthday0916/article/details/126164102