Java基础学习(十五)

Java基础学习(十五):IO流

目录
  • Java基础学习(十五):IO流
    • 概念
    • 基本流
      • 字节输出流 FileOutputStream
      • 字节输入流 FileInputStream
      • 字符集
      • Java 中的编码和解码
      • 字符输入流 FileReader
      • 字符输出流 FileWriter
    • 缓冲流
      • 字节缓冲流
      • 字符缓冲流
    • 转换流
    • 序列化流 和 反序列化流
      • 序列化流
      • 反序列化流
    • 打印流
      • 字节打印流
      • 字符打印流
    • 解压缩流 和 压缩流
      • 解压缩流
      • 压缩流
    • 常用工具包
      • Commons-io
      • Hutool

本文为个人学习记录,内容学习自 黑马程序员


概念

  • 作用:读写文件中的数据

  • 分类:根据流的方向,可以分成输入流和输出流;根据操作文件类型,可以分成字节流和字符流

  • 字节流能够处理所有类型的文件,字符流只能处理纯文本文件

  • 纯文本文件:用 windows 自带的记事本打开不会出现乱码的文件,例如 txt 文件,md 文件,xml 文件等

  • 体系结构:下图中 InputStream,OutputStream,Reader,Writer 均为抽象类,一般直接使用它们的子类,例如使用字节流操作本地文件时的类为 FileInputStream 和 FileOutputStream

    图15-1
  • 可以分成基本流和高级流,高级流包括缓冲流、转换流、序列化流、打印流、压缩流


基本流

字节输出流 FileOutputStream

  • 作用:操作本地文件的字节输出流,可以把程序中的数据写到本地文件中

  • 步骤:1. 创建字节输出流对象 2. 写数据 3. 释放资源

  • 示例:

    public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("aaa\\a.txt");				// 创建对象fos.write(97);															// 写数据fos.close();															// 释放资源
    }
    
  • 注意事项:

    • 创建字节流输出对象时,参数可以是表示路径的字符串,也可以是 File 对象
    • 创建字节流输出对象时,如果路径表示的文件不存在,则会创建一个新的文件,但是必须保证父级路径是存在的;如果路径表示的文件已经存在,则会清空该文件
    • write() 方法的参数是整数,但是实际上写到本地文件中的是整数在 ASCII 码表上对应的字符
    • 每次使用完流后都需要释放资源 ,多个资源需要释放时遵循“先入后出”
  • 写数据的三种方式

    方法名 说明
    void write(int b) 一次写一个字节数据
    void write(byte[] b) 一次写一个字节数组数据
    void write(byte[] b, int off, int len) 一次写一个字节数组的部分数据
    public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("aaa\\a.txt");byte[] bytes = {97, 98, 99};// 方式一:此处向文件中写入"a"fos.write(97);// 方式二:此处向文件中写入"abc"fos.write(bytes);// 方式三:第二个参数为起始索引,第三个参数为长度,此处向文件中写入"ab"fos.write(bytes, 0, 2);fos.close();
    }
    
  • 将字符串写入文件

    考虑到将字符串中的每个字符都到 ASCII 码表中寻找对应的整数较为繁琐,可以使用 String 类中提供的 getBytes() 方法

    public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("aaa\\a.txt");// 采用getBytes()方法将字符串转换成byte数组,再写入String str = "abc";byte[] arr = str.getBytes();fos.write(arr);fos.close();
    }
    
  • 换行

    注意:不同操作系统换行符不同,windows 系统为 \r\n ,linux 系统为 \n ,mac 系统为 \r ,但在 windows 系统中 Java 对此进行了优化,只要写 \r 或者 \n 其中之一就行,Java 会对其自动补全

    public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("aaa\\a.txt");String str1 = "abc";byte[] arr1 = str1.getBytes();fos.write(arr1);// 在需要换行时,通过换行符进行换行String str2 = "\r\n";byte[] arr2 = str2.getBytes();fos.write(arr2);String str3 = "123";byte[] arr3 = str3.getBytes();fos.write(arr3);fos.close();
    }
    
  • 续写

    FileOutputStream 的构造方法中第二个参数表明了是否进行续写,默认为 false,此时会直接清空文件;需要续写时只要将其置为 true 即可

    FileOutputStream fos = new FileOutputStream("aaa\\a.txt", true);
    

字节输入流 FileInputStream

  • 作用:操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中

  • 步骤:1. 创建字节输入流对象 2. 读数据 3. 释放资源

  • 示例:

    public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("aaa\\a.txt");				// 创建对象int b = fis.read();														// 读数据fis.close();															// 释放资源
    }
    
  • 注意事项:

    • 创建字节流输入对象时,如果路径表示的文件不存在则会直接报错
    • read() 方法逐个读取文件中的数据,一次只读一个字节,并将指针移动到下一个字节上,返回值为数据在 ASCII 码表中对应的整数,如果已经读到文件末尾了还继续调用 read() 方法,则返回 -1
    • 每次使用完流后都需要释放资源 ,多个资源需要释放时遵循“先入后出”
  • 循环读取

    public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("aaa\\a.txt");int b;while ((b = fis.read()) != -1) {System.out.print((char) b);}
    }
    
  • 读数据的三种方式

    方法名 说明
    public int read() 一次读一个字节数据
    public int read(byte[] b) 一次读一个字节数组数据(尽可能装满数组)
    public int read(byte[] b, int off, int len) 一次读一个字节数组的部分数据
    public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("aaa\\a.txt");// 创建一个长度为2的byte数组byte[] bytes = new byte[2];// 将byte数组作为参数传入read()方法,会将读取到的数据保存在数组中,返回值为读取的字节数// 如果byte数组中本来就有数据,那么会进行不清空的覆盖// 例如文件中有数据"abcde",数组长度为2,读取4次时返回值依次为2、2、1、-1,byte数组中依次为"ab"、"cd"、"ed"、"ed"int len = fis.read(bytes);// 数组中的每一个元素为读取到的数据在ASCII码表中对应的整数System.out.println(Arrays.toString(bytes));fis.close();
    }
    

字符集

  • ASCII 字符集

    • 总共128个英文字符,每个英文采用 1 字节存储
    • 编码规则:查询英文对应的 ASCII 码值,将其二进制高位补零补齐8位
  • GBK 字符集

    • GBK 是对于 GB2312 的扩展,包含了简体中文、繁体中文、日文、韩文
    • 简体中文版的 windows 系统默认使用的字符集就是 GBK
    • 在不同系统中,ANSI 表示不同字符集,其中简体中文版的 windows 系统中的 ANSI 就是 GBK
    • 英文使用 1 字节存储,完全兼容 ASCII 码;汉字使用 2 字节存储
    • 编码规则:
      • 英文:查询英文对应的 GBK 码值,将其二进制高位补零补齐8位
      • 汉字:查询汉字对应的 GBK 码值,无需对其进行改动
      • 为了将英文和汉字进行区分,汉字的 GBK 码值的二进制一定是以 1 开头,而英文是以 0 开头
  • Unicode 字符集(万国码)

    • 英文完全兼容 ASCII 码

    • 不同版本的编码规则 UTF(Unicode Transfer Format)

      • UTF-8:每个字符采用 1~4 个字节存储(英文采用 1 字节,汉字采用 3 字节)

        UTF-8 编码方式(二进制)
        0xxxxxxx(ASCII 码)
        110xxxxx 10xxxxxx
        1110xxxx 10xxxxxx 10xxxxxx
        11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

        例如:"汉"的 Unicode 码值为 27721,转换成二进制为 01101100 01001001,那么 UTF-8 编码需要对固定格式进行填补,编码后为 11100110 10110001 10001001

      • UTF-16:每个字符采用 2~4 个字节存储

      • UTF-32:每个字符采用 4 个字节存储

Java 中的编码和解码

  • Java 中编码的方法

    String 类中的方法 说明
    public byte[] getBytes() 使用默认方式进行编码(IDEA 默认使用 UTF-8 编码)
    public byte[] getBytes(String charsetName) 使用指定方式进行编码
    String str = "abc你好";
    // 使用默认方式进行编码,此处采用IDEA的默认编码方式UTF-8
    byte[] bytes1 = str.getBytes();
    // 使用指定方式进行编码,可以大写也可以小写
    byte[] bytes2 = str.getBytes("GBK");
    // 打印输出
    System.out.println(Arrays.toString(bytes1));		// 输出为 [97, 98, 99, -28, -67, -96, -27, -91, -67]
    System.out.println(Arrays.toString(bytes2));		// 输出为 [97, 98, 99, -60, -29, -70, -61]
    
  • Java 中解码的方法

    String 类中的方法 说明
    String(byte[] bytes) 使用默认方式进行解码(IDEA 默认使用 UTF-8 解码)
    String(byte[] bytes, String charsetName) 使用指定方式进行解码
    // 使用默认方式进行解码
    String str2 = new String(bytes1);
    // 使用指定方式进行解码
    String str3 = new String(bytes2, "GBK");
    System.out.println(str2);							// 输出为 "abc你好"
    System.out.println(str3);							// 输出为 "abc你好"
    

字符输入流 FileReader

  • 字符流的底层就是字节流,只不过 字符流 = 字节流 + 字符集

  • 步骤:1. 创建字节输入流对象 2. 读数据 3. 释放资源

  • 创建对象

    构造方法 说明
    public FileReader(File file) 创建字符输入流关联本地文件
    public FileReader(String pathname) 创建字符输入流关联本地文件
  • 读取数据

    成员方法 说明
    public int read() 读取数据,读到末尾返回 -1
    public int read(char[] buffer) 读取多个数据,读到末尾返回 -1
  • 释放资源

    成员方法 说明
    public int close() 释放资源/关流
  • 示例:

    public static void main(String[] args) throws IOException {// 空参read()方法// 读取到的数据为码值,需要人为强转成对应字符FileReader fr = new FileReader("aaa\\a.txt");int ch;while ((ch = fr.read()) != -1) {System.out.print((char)ch);}fr.close();System.out.println("\r\n");// 有参read()方法// 保存到char数组中的数据已经强转成对应字符了,无需人为强转FileReader fr2 = new FileReader("aaa\\a.txt");char[] chars = new char[2];int len;while ((len = fr2.read(chars)) != -1) {System.out.print(new String(chars, 0, len));}fr2.close();
    }
    
  • 注意事项:

    • 创建对象时,如果路径表示的文件不存在则会直接报错
    • read() 方法按字节进行读取,遇到中文时一次读取多个字节,读取后解码,返回一个整数
    • 和字节输入流一样,空参的 read() 返回值为数据的码值,有参的 read() 返回值为读取到的数据个数
    • 如果需要将码值转换成对应的字符,还需要使用 (char) 进行强转,此处也会根据 UTF-8 编码方式的码表进行转换
    • 需要注意,字符输入流有参 read() 的形参是 char 数组,而字节输入流有参 read() 的形参是 byte 数组
    • (了解)创建字符输入流对象时,在底层对内存和文件进行了关联,并在内存中创建长度为8192的字节数组作为缓冲区。在读取数据时,如果缓冲区中存在数据,则直接从缓冲区中读取,否则将文件中的数据复制到缓冲区中,并尽可能装满缓冲区,再进行读取。这样做可以不需要每次读取时都从硬盘中读取数据,提高读取效率。需要区分的是,字节流是不会创建缓冲区的!

字符输出流 FileWriter

  • 创建对象

    构造方法 说明
    public FileWriter(File file) 创建字符输出流关联本地文件
    public FileWriter(String pathname) 创建字符输出流关联本地文件
    public FileWriter(File file, boolean append) 创建字符输出流关联本地文件,续写
    public FileWriter(String pathname, boolean append) 创建字符输出流关联本地文件,续写
  • 写数据

    成员方法 说明
    void write(int c) 写出一个字符
    void write(String str) 写出一个字符串
    void write(String str, int off, int len) 写出一个字符串的一部分
    void write(char[], cbuf) 写出一个字符数组
    void write(char[], cbuf, int off, int len) 写出一个字符数组的一部分
  • 示例

    public static void main(String[] args) throws IOException {FileWriter fw = new FileWriter("aaa\\a.txt");// 写出一个字符fw.write(25105);// 写出一个字符串fw.write("你好");// 写出一个字符数组char[] chars = {'a', 'b', '你', '好'};fw.write(chars);fw.close();
    }
    
  • 注意事项

    • 创建字符输出流对象时,参数是表示路径的字符串或者 File 对象都行
    • 创建字符输出流对象时,如果文件不存在则会创建一个新的文件,但是要保证父级路径存在
    • 创建字符输出流对象时,如果文件已经存在,默认情况下会清空该文件,除非将续写开关 append 置为 true
    • write() 方法的参数是整数时,实际上写到本地文件中的是整数在字符集上对应的字符
    • (了解)创建字符输出流对象时,在底层对内存和文件进行了关联,并在内存中创建长度为8192的字节数组作为缓冲区。在下面三种情况时,将缓冲区中的内容保存到本地文件中:1.缓冲区装满了 2.调用 flush 进行刷新 3.调用 close 关流。需要注意,程序执行完毕并不会将缓冲区的内容保存到本地文件。需要区分的是,字节流是不会创建缓冲区的!

缓冲流

目的:缓冲流就是在基本流的基础上使用缓冲区提高读写效率,并封装了其他方法

比较:相比于基本字节流,字节缓冲流能够显著提高效率;而由于基本字符流已经有缓冲区实现了,因此字符缓冲流提高并不明显

图15-2

字节缓冲流

  • 原理:底层自带了长度为 8192 的字节数组缓冲区用于提高性能

  • 创建对象

    方法名 说明
    public BufferedInputStream(InputStream is) 把基本字节输入流包装成字节缓冲输入流,缓冲区大小为 8192
    public BufferedInputStream(InputStream is, int size) 把基本字节输入流包装成字节缓冲输入流,手动设定缓冲区大小
    public BufferedOutputStream(OutputStream os) 把基本字节输出流包装成字节缓冲输出流,缓冲区大小为 8192
    public BufferedOutputStream(OutputStream os, int size) 把基本字节输出流包装成字节缓冲输出流,手动设定缓冲区大小
  • 示例:拷贝文件

    方法一:一次读写一个字节

    public static void main(String[] args) throws IOException {BufferedInputStream bis = new BufferedInputStream(new FileInputStream("aaa\\a.txt"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("aaa\\b.txt"));int b;while ((b = bis.read()) != -1) {bos.write(b);}bos.close();bis.close();
    }
    

    方法二:一次读写一个字节数组

    public static void main(String[] args) throws IOException {BufferedInputStream bis = new BufferedInputStream(new FileInputStream("aaa\\a.txt"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("aaa\\b.txt"));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}bos.close();bis.close();
    }
    
  • 注意事项:调用缓冲流的 close() 方法时,缓冲流在底层会关闭基本流,所以无需手动调用基本流的 close() 方法

字符缓冲流

  • 原理:底层自带了长度为 8192 的字符数组缓冲区用于提高性能

  • 创建对象

    方法名 说明
    public BufferedReader(Reader r) 把基本字符输入流包装成字符缓冲输入流
    public BufferedWriter(Writer r) 把基本字符输出流包装成字符缓冲输出流
  • 特有方法

    字符缓冲输入流特有方法 说明
    public String readLine() 读取一行数据,如果没有数据可读了返回 null
    字符缓冲输出流特有方法 说明
    public void newLine() 跨平台的换行
  • 示例:readLine() 的使用

    public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new FileReader("aaa\\a.txt"));String line = br.readLine();System.out.println(line);br.close();
    }
    
  • 示例:newLine() 的使用

    public static void main(String[] args) throws IOException {BufferedWriter bw = new BufferedWriter(new FileWriter("aaa\\a.txt"));bw.newLine();bw.close();
    }
    
  • 注意事项:

    • readLine() 方法一次读取一整行,遇到换行时结束,但并不会把换行读取到内存中;下一次读取时读取下一行
    • 调用缓冲流的 close() 方法时,缓冲流在底层会关闭基本流,所以无需手动调用基本流的 close() 方法

转换流

  • 概念:转换流是字符流和字节流之间的桥梁

    • 字符转换输入流:InputStreamReader
    • 字符转换输出流:OutputStreamWriter
    图15-3
  • 转换流输入参数为字节流,通过字节流与硬盘建立连接,但其本身是字符流的一种,能使用字符流中的方法

  • 作用:1. 在 JDK11 之前,采用转换流来指定读写的编码方式

    ​ 2. 将字节流转换成字符流,从而在与硬盘交互时使用字节流,但在程序层面能够调用字符流的方法

  • 创建对象常用方法

    构造方法 说明
    public InputStreamReader(InputStream is) 创建转换输入流对象
    public InputStreamReader(InputStream is, String charsetName) 创建转换输入流对象,并指定编码方式
    public OutputStreamWriter(OutputStream os) 创建转换输出流对象
    public OutputStreamWriter(OutputStream os, String charsetName) 创建转换输出流对象,并指定编码方式
  • 示例:利用转换流按照指定字符编码读取数据

    // 在 JDK11 之前采用的方法
    public static void main(String[] args) throws IOException {InputStreamReader isr = new InputStreamReader(new FileInputStream("aaa\\a.txt"), "GBK");int ch;while ((ch = isr.read()) != -1) {System.out.print((char) ch);}isr.close();
    }// 在 JDK11 之后出现的替代方法
    public static void main(String[] args) throws IOException {FileReader fr = new FileReader("aaa\\a.txt", Charset.forName("GBK"));int ch;while ((ch = fr.read()) != -1) {System.out.print((char) ch);}fr.close();
    }
    

    示例:利用转换流按照指定字符编码写出数据

    // 在 JDK11 之前采用的方法
    public static void main(String[] args) throws IOException {OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("aaa\\a.txt"), "GBK");osw.write("123你好");osw.close();
    }// 在 JDK11 之后出现的替代方法
    public static void main(String[] args) throws IOException {FileWriter fw = new FileWriter("aaa\\a.txt", Charset.forName("GBK"));fw.write("abc你好");fw.close();
    }
    
  • 综合应用:

    题目:利用字节流读取文件中的数据,每次读取一行,而且不能出现乱码

    分析:1. 字节流默认按照 UTF-8 编码,要想读取其他编码方式时不出现乱码,需要采用转换流指定编码方式

               2. 要想一次读取一行,只能使用字符缓冲流中的 readLine() 方法3. 因此需要先使用转换流将字节流包装成字符流,再使用缓冲流对字符流进行包装
    
    public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("aaa\\b.txt");InputStreamReader isr = new InputStreamReader(fis, "GBK");BufferedReader br = new BufferedReader(isr);String line;while ((line = br.readLine()) != null) {System.out.print(line);}br.close();
    }
    

序列化流 和 反序列化流

序列化流

  • 概念:序列化流是字节流的一种,又称为对象操作输出流

  • 作用:序列化流可以把 Java 中的对象写到本地文件中

  • 构造方法

    构造方法 说明
    public ObjectOutputStream(OutputStream out) 把基本流包装成序列化流
  • 成员方法

    方法名 说明
    public final void writeObject(Object obj) 把对象序列化(写出)到文件中
  • 示例:

    public class Test {public static void main(String[] args) throws IOException {Student stu = new Student();ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("aaa\\a.txt"));oos.writeObject(stu);oos.close();}
    }class Student implements Serializable {// Javabean内容省略
    }
    
  • 注意事项:

    • 使用对象输出流将对象保存到文件时,该类需要实现 Serializable 接口,否则会报错 NotSerializableException
    • Serializable 接口内没有抽象方法,为标记型接口,不需要重写内容

反序列化流

  • 概念:又称为对象操作输入流

  • 作用:可以把序列化到本地文件中的对象读取到程序中

  • 构造方法

    构造方法 说明
    public ObjectInputStream(InputStream out) 把基本流包装成反序列化流
  • 成员方法

    方法名 说明
    public Object readObject() 把序列化到本地文件中的对象,读取到程序中
  • 示例:

    public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException {ObjectInputStream ois = new ObjectInputStream(new FileInputStream("aaa\\a.txt"));Object o = ois.readObject();System.out.println(o);ois.close();}
    }
    
  • 注意事项:

    • 将对象序列化得到的数据中包含了序列号(版本号),该序列号是由类的成员变量、静态变量等信息计算得到的,在反序列化时会检查序列号是否一致,如果不一致则会报错。比如将对象序列化后,又对类本身进行了修改,此时再尝试反序列化就会报错

    • 固定序列号:在类中添加下面内容,就能固定类的序列号,防止修改类后序列化对象无法正常读取

      private static final long serialVersionUID = 1L;
      
    • 如果想要防止隐私内容被序列化到文件中,可以使用 transient 关键字修饰成员变量,该变量的值不会被保存到文件中,反序列化后该变量的值为默认值

    • 如果文件中存在多个序列化的对象,反序列化时每次只读取一个对象,当读取完还继续读取时,既不会返回 -1 也不会返回 null,而是直接抛出异常,这不利于未知对象个数时的反序列化,因此当需要向一个文件写入多个序列化的对象时,一般先将这些对象保存在一个集合中,再将该集合序列化


打印流

分类:字节打印流 PrintStream,字符打印流 PrintWriter

特点:

  1. 打印流只有输出流,没有输入流
  2. 打印流有特有的写出方法,可以实现原样写出
  3. 打印流的特有写出方法可以实现自动刷新,自动换行

字节打印流

  • 构造方法

    构造方法 说明
    public PrintStream(OutputStream/File/String) 关联字节输出流/文件/文件路径
    public PrintStream(OutputStream out, boolean autoFlush) 自动刷新
    public PrintStream(OutputStream out, boolean autoFlush, String encoding) 指定字符编码且自动刷新
  • 成员方法

    方法名 说明
    public void write(int b) 常规方法:和之前的方法一样,将指定的字节写出
    public void println(Xxx xx) 特有方法:打印任意数据,自动换行
    public void print(Xxx xx) 特有方法:打印任意数据,不换行
    public void printf(String format, Object... args) 特有方法:带有占位符的打印语句,不换行
  • 示例:

    public static void main(String[] args) throws IOException {PrintStream ps = new PrintStream(new FileOutputStream("aaa\\a.txt"), true, "UTF-8");// 原样写出,此处为97,写出的就是97,而非'a'ps.println(97);ps.print(true);ps.printf("%s456", "123");ps.close();
    }
    
  • 注意事项:

    • 字节打印流不存在缓冲区,因此开不开自动刷新没有区别,执行 write/println/print/printf 时就会把数据写入文件中

    • 虽然底层是字节流,但是可以原样打印任意数据,包括汉字

    • printf 中的常用占位符:

      占位符 说明
      %n 换行
      %s 字符串
      %c 大写字母
      %b 布尔类型数据
      %d 小数数据
    • System.out.println:System 是类名,out 是类中的一个 PrintStream 类型的静态变量,它是系统的标准输出流,在虚拟机启动时由虚拟机创建,默认指向控制台,该输出流开启了自动刷新

字符打印流

  • 构造方法

    构造方法 说明
    public PrintWriter(Writer/OutputStream/File/String) 关联字符输出流/字节输出流/文件/文件路径
    public PrintWriter(Writer out, boolean autoFlush) 自动刷新
    public PrintWriter(OutputStream out, boolean autoFlush) 自动刷新
    public PrintWriter(OutputStream out, boolean autoFlush, Charset charset) 指定字符编码且自动刷新,JDK11 才支持
  • 成员方法

    方法名 说明
    public void write(...) 常规方法:和之前的方法一样,写出字节或字符串
    public void println(Xxx xx) 特有方法:打印任意数据,自动换行
    public void print(Xxx xx) 特有方法:打印任意数据,不换行
    public void printf(String format, Object... args) 特有方法:带有占位符的打印语句,不换行
  • 示例:

    public static void main(String[] args) throws IOException {PrintWriter pw = new PrintWriter(new FileWriter("aaa\\a.txt"), true);pw.println("你好");pw.print(true);pw.printf("%s456", "123");pw.close();
    }
    
  • 注意事项:

    • 字符打印流底层有缓冲区,效率更高,但如果想要自动刷新必须将 autoFlush 置为 true

解压缩流 和 压缩流

解压缩流

  • Java 只能识别 .zip 格式的压缩文件

  • Java 中,压缩包中的每个文件都是一个 ZipEntry 对象,因此解压的本质就是把每一个 ZipEntry 按照层级拷贝到本地另一个文件夹中

  • 示例:实现文件的解压

    public class Test {public static void main(String[] args) throws IOException {// 实现功能:将项目下的压缩文件aaa.zip解压到项目下File src = new File("aaa.zip");File dest = new File(".\\");unzip(src, dest);}// 解压方法的实现public static void unzip(File src, File dest) throws IOException {// 创建解压缩流对象ZipInputStream zis = new ZipInputStream(new FileInputStream(src));ZipEntry entry;// 循环遍历压缩文件中的每一个文件/文件夹while ((entry = zis.getNextEntry()) != null) {// 如果遍历到的entry是文件夹,则在本地创建一个相同的文件夹// 如果遍历到的entry是文件,则对文件内容进行拷贝if (entry.isDirectory()) {File file = new File(dest, entry.toString());file.mkdirs();} else {FileOutputStream fos = new FileOutputStream(new File(dest, entry.toString()));int b;// 需要注意,此处调用read()方法的是zis而非entrywhile ((b = zis.read()) != -1) {fos.write(b);}fos.close();// 表示压缩包中的一个文件处理完毕了zis.closeEntry();}}zis.close();}
    }
    
  • 注意事项:

    • 调用 getNextEntry() 方法获取压缩文件中的下一个 ZipEntry 对象,能够遍历所有的文件夹和文件,包括子文件夹中的文件,如果已经遍历完了还继续调用则返回 null

压缩流

  • Java 中,压缩包中的每个文件都是一个 ZipEntry 对象,因此压缩的本质就是把每一个文件/文件夹看成 ZipEntry 对象放到压缩包中

  • 示例:实现单个文件的压缩

    public class Test {public static void main(String[] args) throws IOException {// 实现功能:将项目下的文件a.txt压缩到a.zip中File src = new File("a.txt");File dest = new File(".\\");toZip(src, dest);}// 压缩单个文件的实现public static void toZip(File src, File dest) throws IOException {// 创建压缩流对象ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest, "a.zip")));// 创建压缩对象,指定文件在压缩包内的路径(相对路径)ZipEntry entry = new ZipEntry("a.txt");zos.putNextEntry(entry);FileInputStream fis = new FileInputStream(src);int b;while ((b = fis.read()) != -1) {// 需要注意,write()方法的是zos而非entryzos.write(b);}zos.closeEntry();zos.close();}
    }
    
  • 示例:实现文件夹的压缩

    public static void main(String[] args) throws IOException {// 实现功能:将项目下的文件夹aaa压缩到a.zip中File src = new File("aaa");File dest = new File(".\\");// 创建压缩流对象ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest, "a.zip")));toZip(src, zos, src.getName());zos.close();
    }// 使用递归压缩文件夹中的内容
    public static void toZip(File src, ZipOutputStream zos, String name) throws IOException {File[] files = src.listFiles();for (File file : files) {if (file.isFile()) {ZipEntry entry = new ZipEntry(name + "\\" + file.getName());zos.putNextEntry(entry);FileInputStream fis = new FileInputStream(file);int b;while ((b = fis.read()) != -1) {zos.write(b);}fis.close();zos.closeEntry();} else {toZip(file, zos, name + "\\" + file.getName());}}
    }
    

常用工具包

Commons-io

  • 概念:Commons中包含了许多工具类,Commons-io 是 apache 开源基金组织提供的一组有关 IO 操作的开源工具包

  • 作用:提高 IO 流的开发效率

  • 使用步骤:

    1. 在项目模块中创建一个文件夹:lib
    2. 将 jar 包复制粘贴到 lib 文件夹中
    3. 右键点击 jar 包,选择 Add as Library,再点击 OK
    4. 在类中导包使用
  • 常见方法

    FileUtils类(文件/文件夹相关) 说明
    static void copyFile(File srcFile, File destFile) 复制文件
    static void copyDirectory(File srcDir, File destDir) 复制文件夹
    static void copyDirectoryToDirectory(File srcDir, File destDir) 复制文件夹
    static void deleteDirectory(File directory) 删除文件夹
    static void cleanDirectory(File directory) 清空文件夹
    static String readFileToString(File file, Charset encoding) 读取文件中的数据变成字符串
    static void write(File file, CharSequence data, String encoding) 写出数据
    IOUtils类(流相关) 说明
    public static int copy(InputStream input, OutputStream output) 复制文件
    public static int copyLarge(Reader input, Writer, output) 复制大文件
    public static String readLines(Reader input) 读取数据
    public static void write(String data, OutputStream output) 写出数据

Hutool

  • Hutool 工具包包含了很多工具类,其中 IO 相关的工具类如下:

    相关类 说明
    IOUtil 流操作工具类
    FileUtil 文件读写和操作的工具类
    FileTypeUtil 文件类型判断工具类
    WatchMonitor 目录、文件监听
    ClassPathResource 针对 ClassPath 中资源的访问封装
    FileReader 封装文件读取
    FileWriter 封装文件写入
  • API 文档:Overview (hutool 5.8.35 API)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/880304.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux vm tools 问题

转载vmware tools 失效问题解决方式(Ubuntu 22 以及其他系统) - 知乎 今天新装了Kubuntu 以及 Ubuntu 版本均为 22x,一如既往的操作,最后发现VMware tools失效。 尝试输入vmware-user发现又可以了。 具体表现: 1、窗口分辨率可以缩放,无法复制粘贴,无法复制粘贴文件。 2…

【shell脚本】轻松搞定打包与Shell部署

本篇和大家分享的是springboot打包并结合shell脚本命令部署,重点在分享一个shell程序启动工具,希望能便利工作; 1. profiles指定不同环境的配置 通常一套程序分为了很多个部署环境:开发,测试,uat,线上 等,我们要想对这些环境区分配置文件,可以通过两种方式: 1、通过a…

01 HTML详解

一. HTML语言 HTML是超文本标记语言。超文本:文本、图片、声音、视频、表格、链接等等。 标记:由许许多多的标签组成。二. HTML结构 HTML 代码是由 "标签" 构成的。 形如: <body>hello</body>标签名 (body) 放到 < > 中。大部分标签成对出现。…

HTML详解

一. HTML语言 HTML是超文本标记语言。超文本:文本、图片、声音、视频、表格、链接等等。 标记:由许许多多的标签组成。二. HTML结构 HTML 代码是由 "标签" 构成的。 形如: <body>hello</body>标签名 (body) 放到 < > 中。大部分标签成对出现。…

【Nginx】Nginx 配置页面请求不走缓存 浏览器页面禁用缓存

我是Superman丶 巴韭特锁螺丝 2025年02月07日 08:50 陕西 前言 使用缓存的优点在于减少数据传输,节省网络流量,加快响应速度;减轻服务器压力;提供服务端的高可用性;缺点在于数据的不一致问题;增加成本 Nginx作为Web缓存服务器,介于客户端和应用服务器之间,当用户通过浏…

NLog日志(三)

程序开发日志输出常用逻辑 1.应用启动和关闭添加新配置<rules><!-- 默认日志记录器(仅控制台输出) --><logger name="*" minlevel="Debug" writeTo="logconsole" /><!-- 记录应用启动 & 关闭日志 --><logger n…

XXL-CACHE v1.2.0 | 多级缓存框架

Release Notes1、【增强】多序列化协议支持:针对L2缓存,组件化抽象Serializer,可灵活扩展更多序列化协议; 2、【优化】移除冗余依赖,精简Core体积;XXL- CACHE 快速接入示例代码参考github仓库 /test 目录:https://github.com/xuxueli/xxl-cache/tree/master/xxl-cache-s…

将模型api集成到python中

1.今日成果 1-1从阿里百炼上获取使用API的代码,在本地配置好环境,运行。 1-2ollama上拉取视频理解的模型,却没有上传视频的界面,可以使用python代码加载模型 1-3huggingface上的模型可以通过transformer集成到python运行。 1-4Qwen模型本地部署的环境搭建好了 2.未解决的问…

注解反射之使用Class对象获取注解

代码如下package com.loubin;import java.lang.annotation.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;public class Main {public static void main(S…

ACM寒假集训第三次专题任务

ACM寒假集训第三次专题任务 一、Priority Queue 题目:解题思路: 对优先队列的直接运用,直接翻译题目即可。 AC代码: #include<iostream> #include<string> #include<queue> using namespace std; int main() {int k;string operation;priority_queue<…

一款基于 WPF 开源、功能全面的串口调试工具

前言 今天大姚给大家分享一款基于 WPF 开源(MIT License)、免费、功能全面的串口调试工具:BYSerial。 项目介绍 BYSerial是一款基于 WPF 开源(MIT License)、免费、功能全面的串口调试工具,支持中英文双语切换,具有通用串口调试工具的一般功能,如串口通讯调试、TCP通讯…

NLog日志(二)

NLog //日志输出builder.Logging.ClearProviders();builder.Logging.AddNLog("nlog.config");配置后默认自动全部输出需求:自动记录的输出到控制台,手动记录的输出到日志文件1.配置两个日志记录器 一个控制台,一个日志文件<rules><!-- 默认日志记录器(…