Java SE 学习笔记(十四)—— IO流(3)

目录

  • [1 缓冲流](#1 缓冲流)
    • [1.1 缓冲流概述](#1.1 缓冲流概述)
    • [1.2 字节缓冲流](#1.2 字节缓冲流)
    • [1.3 字符缓冲流](#1.3 字符缓冲流)
  • [2 转换流](#2 转换流)
    • [2.1 字符输入转换流](#2.1 字符输入转换流)
    • [2.1 字符输出转换流](#2.1 字符输出转换流)
  • [3 序列化](#3 序列化)
    • [3.1 对象序列化](#3.1 对象序列化)
    • [3.2 对象反序列化](#3.2 对象反序列化)
  • [4 打印流](#4 打印流)
  • [5 与Properties结合使用](#5 与Properties结合使用)
  • [6 IO 框架](#6 IO 框架)

1 缓冲流

1.1 缓冲流概述

我们之前学习的字节流、字符流属于基础流、原始流,性能其实不是最好的,缓冲流读写数据的性能更好

缓冲流也称为高效流、高级流,其自带缓冲区,可以提高原始字节流、字符流读写数据的性能。功能上并无很大变化,性能提升了。

1.2 字节缓冲流

字节缓冲输入流:

  • BufferedInputStream ,提高字节输入流读取数据的性能。
  • 字节缓冲输入流自带了 8KB 缓冲池,以后我们直接从缓冲池读取数据,所以性能较好。

字节缓冲输出流:

  • BufferedOutputStream ,提高字节输出流读取数据的性能。
  • 字节缓冲输出流自带了 8KB 缓冲池,数据就直接写入到缓冲池中去,写数据性能极高了。

构造方法

为什么构造方法需要的是字节流,而不是具体的文件或者路径呢?

  • 字节缓冲流仅仅提供缓冲区,而真正读写数据还是得依靠基本的字节流对象进行操作

1.3 字符缓冲流

符缓冲输入流:

  • BufferedReader,提高字符输入流读取数据的性能,除此之外多了按照行读取数据的功能。


字符缓冲输出流:

  • BufferedWriter ,提高字符输出流写取数据的性能,除此之外多了换行功能

示例代码:

java 复制代码
import java.io.*;

public class Test1 {
    public static void main(String[] args) throws IOException {
        FileWriter f1 = new FileWriter("D:\\StudyTools\\test.txt");
        BufferedWriter bw = new BufferedWriter(f1);

        bw.write("我");
        bw.write("abc");
        bw.newLine();
        bw.write("hhhh");
        bw.close(); // 字符首先写到缓冲池,关闭文件后刷新,写入的文件有内容显示

        FileReader f2 = new FileReader("D:\\StudyTools\\test.txt");
        BufferedReader br = new BufferedReader(f2);
        System.out.println(br.readLine()); // 我abc
        System.out.println(br.readLine()); // hhhh
        System.out.println(br.readLine()); // null
    }
}

推荐使用哪种方式提高字节流读写数据的性能?

  • 建议使用字节缓冲输入流、字节缓冲输出流,结合字节数组的方式, 目前来看是性能最优的组合。

2 转换流

使用字符流读取中文不会乱码,那如果读取的文件编码与代码编码不一致怎么办呢?

2.1 字符输入转换流

针对文件编码与代码编码不一致导致的乱码问题,如何解决?

  • 使用字符输入转换流
    • 可以提取文件的原始字节流(原始字节不会存在问题)
    • 然后把字节流以指定编码转换成字符输入流(这样字符输入流的字符就不会乱码了)

字符输入转换流: InputStreamReader ,可以把原始的字节流按照指定编码转换成字符输入流。

示例代码:

java 复制代码
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/*
* 代码是UTF-8,文件是GBK
* */
public class Test1 {
    public static void main(String[] args) throws IOException {
        // 1. 提取字节码文件的原始字节流
        FileInputStream f = new FileInputStream("D:\\StudyTools\\test.txt");
        // 2. 把原始字节流转换为字符输入流
//        InputStreamReader isr = new InputStreamReader(f); // 默认UTF-8转换字符流还是会乱码
        InputStreamReader isr = new InputStreamReader(f,"GBK");
        BufferedReader br = new BufferedReader(isr);
        String s;
        while((s=br.readLine())!=null){
            System.out.println(s);
        }
    }
}

2.1 字符输出转换流

如果需要控制写出去的字符使用的编码,怎么办?

  • 可以把字符以指定编码获取字节后再使用字节输出流写出去
    • "我爱你中国" .getBytes(编码)
  • 也可以使用字符输出转换流实现

字符输出转换流: OutputStreamWriter ,可以指定编码把字节输出流转换成字符输出流,从而可以指定写出去的字符编码

示例代码:

java 复制代码
import java.io.*;

/*  代码是UTF-8
    指定写出去文件的字符编码GBK
* */

public class Test {
    public static void main(String[] args) throws IOException {
        // 1. 定义一个字节输出流
        FileOutputStream os = new FileOutputStream("io/src/out.txt");
        // 2. 把原始的字节输出流转换成字符输出流
        OutputStreamWriter osw = new OutputStreamWriter(os,"GBK");
        BufferedWriter bw = new BufferedWriter(osw);
        bw.write("123我爱你中国");
        bw.write("123我爱你中国");
        bw.newLine();
        bw.write("123我爱你中国");
        bw.close();
    }
}

3 序列化

如何把Java对象进行长久的保存?

3.1 对象序列化

对象序列化:

  • 以内存为基准,把内存中的对象存储到磁盘文件中去。
  • 使用到的流是对象字节输出流ObjectOutputStream

构造方法

序列化方法

示例代码

学生对象

java 复制代码
import java.io.Serializable;

public class Student implements Serializable {
	// 声明序列化的版本号
    private static final long serialVerionUID=1;
    private int age;
    private String name;
    private String passwd;
    // private transient String passwd; // 表示修饰的成员变量不参与序列化

    public Student() {
    }

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

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

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

序列化

java 复制代码
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Test {
    public static void main(String[] args) throws IOException {
        // 1. 创建学生对象
        Student s = new Student(18, "小明", "123123");
        // 2. 对象序列化
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("io/src/obj.txt"));
        // 3. 调用序列化方法
        oos.writeObject(s);
        oos.close();
    }
}

注意:

  • 对象如果要序列化,必须实现 Serializable接口
    • 一个标记性接口,里面没有任何的抽象方法(实现一个接口就要实现里面所有的抽象方法)只要一个类实现了这个Serializable接口,那么就表示这个类的对象可以被序列化。
    • 实现该接口,不需要重写任何方法
  • transien修饰的成员变量不参与序列化
  • 序列化与反序列化的版本号必须一致

3.2 对象反序列化

对象反序列化:

  • 以内存为基准,把存储到磁盘文件中去的对象数据恢复成内存中的对象
  • 使用到的流是对象字节输入流ObjectInputStream

构造方法

反序列方法

示例代码

java 复制代码
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 1. 对象反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("io/src/obj.txt"));
        // 2. 调用反序列化方法
        Student s = (Student)ois.readObject();
        System.out.println(s);
        ois.close();
    }
}

4 打印流

开发中有一种使用极为方便,性能高效的写数据的流,使用的很多。

打印流可以实现方便高效 的打印数据到文件中去。打印流一般是指: PrintStreamPrintWriter 两个类。

可以实现打印什么数据就是什么数据,例如打印整数 97 写出去就是 97 ,打印 boolean 的 true ,写出去就是 true 。

构造方法

打印方法(二者一样)

示例代码

java 复制代码
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

public class printDemo {
    public static void main(String[] args) throws FileNotFoundException {
        // 创建一个打印流对象
//        PrintStream ps = new PrintStream("io/src/ps.txt");
//        PrintStream ps = new PrintStream(new File("io/src/ps.txt"));
        PrintStream ps = new PrintStream(new FileOutputStream("io/src/ps.txt"));// 如果要追加数据,在低级管道后面加true

        ps.println(true);
        ps.println("我爱你中国");
        ps.println(123);
        ps.close();
    }
}

PrintStreamPrintWriter 的区别

  • 打印数据功能上是一模一样的,都是使用方便,性能高效(核心优势)
  • PrintStream 继承自字节输出流 OutputStream ,支持写字节数据的方法。
  • PrintWriter 继承自字符输出流 Writer ,支持写字符数据出去。

输出语句重定向:属于打印流的一种应用,可以把输出语句的打印位置改到文件

java 复制代码
import java.io.FileNotFoundException;
import java.io.PrintStream;

public class printDemo {
    public static void main(String[] args) throws FileNotFoundException {
        // 控制台打印
        System.out.println("床前明月光,");
        System.out.println("疑是地上霜。");
        // 改变输出语句的位置(将以下两句输出到文件)
        PrintStream ps = new PrintStream("io/src/print.txt");
        System.setOut(ps);
        System.out.println("举头望明月,");
        System.out.println("低头思故乡。");
    }
}

5 与Properties结合使用

Properties 集合是一个Map体系的集合类,但是一般我们不会当集合使用,因为HashMap更好用,其可以保存到流中或从流中加载。

Properties核心作用Properties 代表的是一个属性文件,可以把自己对象中的键值对信息存入到一个属性文件中去。

  • 属性文件:后缀是 .properties 结尾的文件 , 里面的内容都是 key=value ,后续做系统配置信息的。(那么这就涉及到文件内容的读写了,结合IO流)

Properties 和 IO 流结合的方法:

示例代码:

java 复制代码
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class PropertiesDemo {
    public static void main(String[] args) throws IOException {
        // 1. 使用Properties将键值对信息保存到属性文件中去(写)
//        Properties p = new Properties();
//        p.setProperty("admin","123456");
//        p.setProperty("huwei","000000");
//        p.setProperty("anni","888888");
//        p.store(new FileWriter("io/src/users.properties"),"这是备注信息");

        // 2. Properties读取属性文件中的属性信息(读)
        Properties properties = new Properties();
        System.out.println(properties);
        // 加载属性文件中的键值对数据到属性对象properties中去
        properties.load(new FileReader("io/src/users.properties"));
        System.out.println(properties);
 		// 获取属性值
        String rs1 = properties.getProperty("admin");
        System.out.println(rs1); // 123456
    }
}

6 IO 框架

commons-io 是 apache 开源基金组织提供的一组有关 IO 操作的类库,可以提高 IO 功能开发的效率。commons-io 工具包提供了很多有关 io 操作的类。有两个主要的类 FileUtilsIOUtils

FileUtils 主要有如下方法:

导入 commons-io-2.15.0.jar ,用其简化 IO 流读写

  • 在项目中创建一个文件夹 lib
  • commons-io-2.15.0.jar文件复制到 lib 文件夹
  • 在 jar 文件上点击右键,选择Add as Library,点击OK
  • 在类中导包使用

示例代码

java 复制代码
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

import java.io.*;

public class CommonsDemo {
    public static void main(String[] args) throws IOException {
        // 文件的复制
        IOUtils.copy(new FileInputStream("io/src/ps.txt"), new FileOutputStream("io/src/ps_copy.txt"));
        // 文件复制到某个文件夹下
        FileUtils.copyFileToDirectory(new File("io/src/ps.txt"),new File("D:\\"));
        // 文件夹复制到某个文件夹下
        FileUtils.copyDirectoryToDirectory(new File("io/src"),new File("D:\\"));
        // 删除文件夹(有内容)
        FileUtils.deleteDirectory(new File("D:\\src"));
        // 删除文件
        FileUtils.delete(new File("D:\\ps.txt"));
    }
}
相关推荐
努力变厉害的小超超2 小时前
ArkTS中的组件基础、状态管理、样式处理、class语法以及界面渲染
笔记·鸿蒙
秃头佛爷2 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
阿伟*rui2 小时前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel
XiaoLeisj4 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck4 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei4 小时前
java的类加载机制的学习
java·学习
Yaml46 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~6 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616886 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
aloha_7896 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot