Java 基础进阶篇(十五):IO 流总结(全网最全面)

news2024/11/26 0:51:49

文章目录

  • 前置内容:字符集
  • 一、IO 流概述
  • 二、字节流
    • 2.1 文件字节输入流 FileInputStream
      • 2.1.1 案例:每次读取一个字节
      • 2.1.2 案例:每次读取一个字节数组
      • 2.1.3 案例:读取文件的全部字节
    • 2.2 文件字节输出流 FileOutputStream
    • 2.3 文件拷贝
    • 2.4 资源释放的方式
      • 2.4.1 try-catch-finally
      • 2.4.2 try-with-resource
  • 三、字符流
    • 3.1 文件字符输入流 FileReader
    • 3.2 文件字符输出流 FileWriter
  • 四、缓冲流
    • 4.1 字节缓冲流
      • 4.1.1 字节缓冲输入流 BufferedInputStream
      • 4.1.2 字节缓冲输出流 BufferedOutputStream
    • 4.2 字符缓冲流
      • 4.2.1 字符缓冲输入流 BufferedReader
      • 4.2.2 字符缓冲输出流 BufferedWritter
  • 五、转换流
    • 5.1 字符输入转换流 InputStreamReader
    • 5.2 字符输出转换流 OutputStreamWrite
  • 六、序列化流
    • 6.1 对象序列化与反序列化
    • 6.2 对象字节输出流 ObjectOutputStream
    • 6.3 对象字节输入流 ObjectInputStream
  • 七、打印流
    • 7.1 PrintStream
    • 7.2 PrintWriter
    • 7.3 PrintStream 和 PrintWriter 的区别
  • 补充:Commons-IO 框架


前置内容:字符集

字符集(Character Set)是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同。

常见的字符集有:ASCII、GBK、Unicode(UTF-8)字符集等。

  • ASCII 字符集:包括了数字、英文、符号。
    ASCII 字符集中一个字符存储 1 个字节,一个字节是 8 位,总共可以表示 128 个字符信息,对于表示英文、数字来说是够用的。

  • GBK 字符集:是中国的码表,包含了几万个汉字等字符
    GBK 字符中一个中文字符一般以 2 个字节的形式存储,同时兼容 ASCII 编码表

  • Unicode 字符集 :又叫统一码、万国码,其容纳了世界上大多数国家的常见文字和字符,是计算机科学领域里的一项业界标准。
    UTF-8 是 Unicode 字符集的一种常见编码方式,用于将数字转换成二进制。
    UTF-8 编码后一个中文一般以 3 个字节的形式存储,同时兼容 ASCII 编码表

中文存储和展示流程解析:

在这里插入图片描述

注意:

① 英文和数字不会乱码;
② 英文和数字等在任何国家的字符集中都占 1 个字节;
③ 字符解码时使用的字符集和编码时使用的字符集必须一致,否则会出现中文乱码;


字符集的编码、解码操作:

String 编码:

在这里插入图片描述

String 解码:

在这里插入图片描述

举例:

public class Test {
    public static void main(String[] args) throws Exception {
        // 1、编码:把文字转换成字节(使用指定的编码)
        String name = "abc我爱你中国";
        byte[] bytes = name.getBytes(); // 以当前代码默认字符集进行编码 (UTF-8)
        //byte[] bytes = name.getBytes("GBK"); // 指定编码
        System.out.println(bytes.length); // 18 abc占三个字节,5个汉字各占三个字节,一共 18
        System.out.println(Arrays.toString(bytes)); 
        // [97, 98, 99, -26, -120, -111, -25, -120, -79, -28, -67, -96, -28, -72, -83, -27, -101, -67]

        // 2、解码:把字节转换成对应的中文形式(编码前 和 编码后的字符集必须一致,否则乱码 )
        String rs = new String(bytes); // 默认的UTF-8
        // String rs = new String(bytes, "GBK"); // 指定GBK解码
        System.out.println(rs); // abc我爱你中国
    }
}

一、IO 流概述

I 表示 intput,负责读,把硬盘文件中的数据读入到内存的过程,称之输入。
O 表示 output,负责写,把内存中的数据写出到硬盘文件的过程,称之输出。

IO流的分类:按照流的方向分为输入流与输出流,若按照流中数据的最小单位可分为字节流与字符流。

在这里插入图片描述
IO 流的四大类:

字节输入流: 以内存为基准,来自磁盘文件/网络中的数据 以字节的形式读入到内存中去
字节输出流: 以内存为基准,把内存中的数据 以字节写出到磁盘文件或者网络中去
字符输入流: 以内存为基准,来自磁盘文件/网络中的数据 以字符的形式读入到内存中去
字符输出流: 以内存为基准,把内存中的数据 以字符写出到磁盘文件或者网络介质中去

IO 流的体系如下:

在这里插入图片描述


二、字节流

2.1 文件字节输入流 FileInputStream

以内存为基准,来自磁盘文件/网络中的数据 以字节的形式读入到内存 中去。

在这里插入图片描述

构造方法:
在这里插入图片描述

常用方法:

在这里插入图片描述


2.1.1 案例:每次读取一个字节

示例:

public class FileInputStreamDemo01 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个文件字节输入流管道与源文件接通。
        // InputStream is = new FileInputStream(new File("day09-oop/src/data.txt"));// ab3
        // 简化写法
        InputStream is = new FileInputStream("day09-oop/src/data.txt");

        // 2、读取一个字节返回 (每次读取一滴水)
		//int b1 = is.read();
        System.out.println((char)is.read()); // a

        int b2 = is.read();
        System.out.println((char)b2); // b

        int b3 = is.read();
        System.out.println((char)b3); // 3

        int b4 = is.read(); // 读取完毕返回-1
        System.out.println(b4); // -1
    }
}

上文案例的循环改进版本:

public class FileInputStreamDemo01 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个文件字节输入流管道与源文件接通。
        InputStream is = new FileInputStream("day09-oop/src/data.txt");// ab3

        // 2、使用循环改进
        int b;
        while (( b = is.read() ) != -1){
            System.out.print((char) b);
        }
    }
}

问题分析:由于中文字符占3个字节,每次读取一个字符会出现乱码问题。


2.1.2 案例:每次读取一个字节数组

示例2: 每次读取一个字节数组(可以理解为一桶水)

public class FileInputStreamDemo03 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个文件字节输入流管道与源文件接通
        InputStream is = new FileInputStream("day09-oop/src/data02.txt"); // abcdefgh

        // 2、定义一个字节数组,用于读取字节数组
        byte[] buffer = new byte[3]; // 3B
        int len1 = is.read(buffer);
        System.out.println("读取了几个字节:" + len1); // 3
        String rs1 = new String(buffer);
        System.out.println(rs1); // abc

        int len2 = is.read(buffer);
        System.out.println("读取了几个字节:" + len2); // 3
        String rs2 = new String(buffer);
        System.out.println(rs2); // def

        int len3 = is.read(buffer);
        System.out.println("读取了几个字节:" + len3); // 2
        // 读取多少倒出多少
        String rs3 = new String(buffer,0 ,len2);// gh
        String rs4 = new String(buffer); // ghf
        System.out.println(rs3);

        int len4 = is.read(buffer);
        System.out.println(len4); // 读取完毕返回-1
	}
}

问题分析1:为什么上文案例当读到 “第三桶水” 的时候,桶里面的水不是 gh,而是 ghf

int len3 = is.read(buffer);
System.out.println("读取了几个字节:" + len3); // 2
// 读取多少倒出多少
String rs3 = new String(buffer,0 ,len2);// gh
String rs4 = new String(buffer); // ghf

原因在于:当读完 “第二桶水” 的时候,字节数组 buffer 中装有的水是 def,当继续从读取的时候,由于只有前两滴水可被读到桶中,因此最终桶里的水只有 ghf

在这里插入图片描述
上文案例的循环改进版本:

public class FileInputStreamDemo04 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个文件字节输入流管道与源文件接通
        InputStream is = new FileInputStream("day09-oop/src/data02.txt"); // abcdefgh
		
		// 2、循环改进
		byte[] buffer = new byte[3];
        int len; // 记录每次读取的字节数。
        while ((len = is.read(buffer)) != -1) {
            // 读取多少倒出多少
            System.out.print(new String(buffer, 0 , len));
        }
	}
}

问题分析2:读取中文字符输出无法避免乱码问题。

例:读取内容为 ab巴s啦啦c 时,每次读取三个字节,会出现乱码问题。


2.1.3 案例:读取文件的全部字节

方式一: 定义一个字节数组与文件的大小一样大,然后使用读取字节数组的方法,一次性读取完成。

方式二: 字节输入流 InputStream 提供了如下 API 可以直接把文件的全部数据读取到一个字节数组中。

在这里插入图片描述

public class FileInputStreamDemo05 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个文件字节输入流管道与源文件接通
        File f = new File("day09-oop/src/data3.txt");
        InputStream is = new FileInputStream("day09-oop/src/data3.txt");

        // 2、定义一个字节数组与文件的大小刚刚一样大。
        // byte[] buffer = new byte[(int) f.length()];
        // int len = is.read(buffer);
        // System.out.println("读取了多少个字节:" + len);
        // System.out.println("文件大小:" + f.length());
        // System.out.println(new String(buffer));

        // 读取全部字节数组
        byte[] buffer = is.readAllBytes();
        System.out.println(new String(buffer));
    }
}

问题分析:不会有中文乱码,但如果文件过大,字节数组可能引起内存溢出


2.2 文件字节输出流 FileOutputStream

以内存为基准,把内存中的数据 以字节写出到磁盘文件或者网络中去

在这里插入图片描述

构造方法:
在这里插入图片描述

常用方法:
在这里插入图片描述

流的刷新与关闭:
在这里插入图片描述

示例:

public class OutputStreamDemo01 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个文件字节输出流管道与目标文件接通
        // OutputStream os = new FileOutputStream("day09-oop/src/out04.txt" , true); // 追加数据管道
        OutputStream os = new FileOutputStream("day09-oop/src/out04.txt"); // 先清空之前的数据,写新数据进入

        // 2、写数据出去
        // a.public void write(int a):写一个字节出去
        os.write('a'); // 自动转换成整型
        os.write(98);
        os.write("\r\n".getBytes()); // 添加换行,win和其他系统都支持换行
        // os.write('徐'); // [ooo]

        // b.public void write(byte[] buffer):写一个字节数组出去。
        byte[] buffer = {'a' , 97, 98, 99};
        os.write(buffer);
        os.write("\r\n".getBytes()); // 添加换行

        byte[] buffer2 = "我是中国人".getBytes();
        // byte[] buffer2 = "我是中国人".getBytes("GBK");
        os.write(buffer2);
        os.write("\r\n".getBytes());

        // c. public void write(byte[] buffer , int pos , int len):写一个字节数组的一部分出去。
        byte[] buffer3 = {'a',97, 98, 99};
        os.write(buffer3, 0 , 3);// 左闭右开,写前三个字符
        os.write("\r\n".getBytes());

        // os.flush(); // 写数据必须,刷新数据 可以继续使用流
        os.close(); // 释放资源,包含了刷新的!关闭后流不可以使用流对象
    }
}

2.3 文件拷贝

在这里插入图片描述

思路:

① 根据数据源创建字节输入流对象。
② 根据目的地创建字节输出流对象。
③ 定义一个字节数组进行数据的转移。
④ 释放资源。

实现:

public class CopyDemo {
    public static void main(String[] args) {
        try {
            // 1、创建一个字节输入流管道与原视频接通
            InputStream is = new FileInputStream("day09-oop/src/data.txt");
            // 2、创建一个字节输出流管道与目标文件接通
            OutputStream os = new FileOutputStream("day09-oop/src/copy.txt");
            
            // 3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len; // 记录每次读取的字节数。
            while ((len = is.read(buffer)) != -1){
                os.write(buffer, 0 , len);
            }
            
            // 4、关闭流。
            os.close();
            is.close();
        } catch (Exception e){
            e.printStackTrace();
        }
   }
}

任何文件的底层都是字节,只要前后文件格式、编码一致没有任何问题,字节流可以完成一切文件数据的拷贝。

总结:字节流适合做文件数据的拷贝,但不适合做中文数据的输出


2.4 资源释放的方式

2.4.1 try-catch-finally

finally: 放在 try-catch 后面的,无论是正常执行还是异常执行代码,最后一定要执行,除非 JVM 退出。

作用:一般用于进行最后的资源释放操作(专业做法)

在这里插入图片描述


2.4.2 try-with-resource

上文的资源虽然可行,但是释放资源的代码过于繁琐,如下文:
在这里插入图片描述
finally{...} 中判断是否为空,是因为有可能在得到流对象之前出现了异常的情况;
finally{...} 中再次 try catch 是因为系统认为可能在上文 try 未结束时已经关闭了流。

JDK 7 和 JDK 9 中都简化了资源释放操作:

在这里插入图片描述
JDK7 以及 JDK9 的改进方案中只能放置资源对象,否则报错。(注:资源都是实现了Closeable/AutoCloseable 接口的类对象)

如:

public abstract class InputStream implements Closeable {...}
public abstract class OutputStream implements Closeable, Flushable{...} 

示例1: JDK7 做法

public class TryCatchResourceDemo2 {
    public static void main(String[] args) {
        try (
                // 这里面只能放置资源对象,用完会自动关闭:自动调用资源对象的close方法关闭资源
                // 即使出现异常也会做关闭操作
                // 1、创建一个字节输入流管道与原视频接通
                InputStream is = new FileInputStream("day09-oop/src/data.txt");
                // 2、创建一个字节输出流管道与目标文件接通
                OutputStream os = new FileOutputStream("day09-oop/src/copy02.txt");

                // int age = 23; //报错,这里只能放资源
                MyConnection connection = new MyConnection(); // 模拟资源对象,最终会自动调用资源的close方法
                ) {              
            // 3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len; // 记录每次读取的字节数。
            while ((len = is.read(buffer)) != -1){
                os.write(buffer, 0 , len);
            }
            System.out.println("复制完成了!");
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

class MyConnection implements AutoCloseable{
    @Override
    public void close() throws IOException {
        System.out.println("连接资源被成功释放了!");
    }
}

示例2: JDK9 做法

public class TryCatchResourceDemo3 {
    public static void main(String[] args) throws Exception {
        // 这里面只能放置资源对象,用完会自动关闭:自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)
        // 1、创建一个字节输入流管道与原视频接通
        InputStream is = new FileInputStream("day09-oop/src/data.txt");
        // 2、创建一个字节输出流管道与目标文件接通
        OutputStream os = new FileOutputStream("day09-oop/src/copy03.txt");
        MyConn conn = new MyConn(); // 最终会自动调用资源的close方法

        try ( is; os; conn ) {
            // 3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len; // 记录每次读取的字节数。
            while ((len = is.read(buffer)) != -1){
                os.write(buffer, 0 , len);
            }
            System.out.println("复制完成了!");

        } catch (Exception e){
            e.printStackTrace();
        }
    }
}
class MyConn implements AutoCloseable{
    @Override
    public void close() throws IOException {
        System.out.println("连接资源被成功释放了~~~");
    }
}

三、字符流

字节流适合做文件拷贝,但是读取中文会出现乱码或者内存溢出。

字符流则可以完全解决这个问题,其把中文和英文数字都当成一个字符来处理。

3.1 文件字符输入流 FileReader

以内存为基准,来自磁盘文件/网络中的数据 以字符的形式读入到内存中去

构造器:
在这里插入图片描述
常用方法:
在这里插入图片描述

示例1: 每次读取一个字符

public class FileReaderDemo01 {
    public static void main(String[] args) throws Exception {
        // 1. 创建一个字符输入流与源文件接通
        Reader fr = new FileReader("day09-oop/src/data3.txt");

        // 2. 读取一个字符,若没有可读字符返回-1
        /*int code = fr.read();
        System.out.println((char)code); // 单个中文一个字符

        int code1 = fr.read();
        System.out.println((char)code1);*/

        // 循环读取
        int code;
        while((code = fr.read()) != -1){
            System.out.print((char)code);
        }
    }
}

注:如果代码文件编码一致,读取中文字符不会出现乱码;读取性能较慢

示例2: 每次读取一个字符数组

public class FileReaderDemo02 {
    public static void main(String[] args) throws Exception {
        // 1. 创建一个字符输入流与源文件接通
        Reader fr = new FileReader("day09-oop/src/data3.txt");

        // 2. 用循环,每次读取一个字符数组的数据
        char[] buffer = new char[1024]; // 1K 字符
        int len;
        while((len = fr.read(buffer)) != -1){
            String rs = new String(buffer, 0, len); // 解码并输出
            System.out.print(rs);
        }
    }
}

注:读取的性能得到了提升;读取中文字符输出不会乱码


3.2 文件字符输出流 FileWriter

以内存为基准,把内存中的数据 以字符写出到磁盘文件或者网络介质中去

构造器:
在这里插入图片描述

常用方法:
在这里插入图片描述

流的关闭与刷新:
在这里插入图片描述

示例:

public class FileWriterDemo03 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个字符输出流管道与目标文件接通
        Writer fw = new FileWriter("day09-oop/src/out04.txt"); // 覆盖管道,每次启动都会清空文件之前的数据
        // Writer fw = new FileWriter("day09-oop/src/out05.txt", true); // 追加数据

        // a.public void write(int c):写一个字符出去
        fw.write('c');
        fw.write(98);
        fw.write('爱');

        // b.public void write(String c)写一个字符串出去
        fw.write("我是中国人");
        fw.write("\r\n");

        // c.public void write(char[] buffer):写一个字符数组出去
        char[] chars = "我是中国人".toCharArray();
        fw.write(chars);

        // d.public void write(String c ,int pos ,int len):写字符串的一部分出去
        fw.write("我是中国人", 0, 3);

        // e.public void write(char[] buffer ,int pos ,int len):写字符数组的一部分出去
        fw.write("我是中国人".toCharArray(), 0, 3);

        // fw.flush(); // 刷新后流可以继续使用
        fw.close(); // 关闭包含刷线,关闭后流不能使用
    }
}

四、缓冲流

缓冲流也称为高效流、或者高级流。之前学习的字节流、字符流可以称为原始流。

作用:缓冲流自带 8KB 缓冲区、可以提高原始字节流、字符流读写数据的性能

4.1 字节缓冲流

字节缓冲流性能优化原理:
字节缓冲输入流自带了 8KB 缓冲池,以后我们直接从缓冲池读取数据,所以性能较好。
字节缓冲输出流自带了 8KB 缓冲池,数据就直接写入到缓冲池中去,写数据性能极高了。
在这里插入图片描述

4.1.1 字节缓冲输入流 BufferedInputStream

字节缓冲输入流:BufferedInputStream,提高字节输入流读取数据的性能。

4.1.2 字节缓冲输出流 BufferedOutputStream

字节缓冲输出流:BufferedOutputStream,提高字节输出流读取数据的性能。

构造方法:
在这里插入图片描述

示例:

public class ByteBufferDemo {
    public static void main(String[] args) {
        try (
                // 这里面只能放置资源对象,用完会自动关闭:自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)
                // 1、创建一个字节输入流管道与原视频接通
                InputStream is = new FileInputStream("day10-oop/src/csb.txt");
                // a.把原始的字节输入流包装成高级的缓冲字节输入流
                InputStream bis = new BufferedInputStream(is); // 多态
                // 2、创建一个字节输出流管道与目标文件接通
                OutputStream os = new FileOutputStream("day10-oop/src/copy01.txt");
                // b.把字节输出流管道包装成高级的缓冲字节输出流管道
                OutputStream bos = new BufferedOutputStream(os);
        ) {
            // 3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len; // 记录每次读取的字节数。
            while ((len = bis.read(buffer)) != -1){
                bos.write(buffer, 0 , len);
            }
            System.out.println("复制完成了!");

        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

4.2 字符缓冲流

4.2.1 字符缓冲输入流 BufferedReader

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

构造器:
在这里插入图片描述
独有方法:
在这里插入图片描述

示例1:

public class BufferedReaderDemo1 {
    public static void main(String[] args) {
        try(
            // 1、创建一个文件字符输入流与源文件接通。
            Reader fr = new FileReader("day10-oop\\src\\csb.txt");
            // a、把低级的字符输入流包装成高级的缓冲字符输入流。
            BufferedReader br = new BufferedReader(fr); // 多态下调用子类方法,只能强转或不用多态
        ) {
            // 2、用循环,每次读取一个字符数组的数据。  1024 + 1024 + 8
            char[] buffer = new char[1024]; // 1K字符
            int len;
            while ((len = br.read(buffer)) != -1) {
                String rs = new String(buffer, 0, len);
                System.out.print(rs);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

示例2:

public class BufferedReaderDemo2 {
    public static void main(String[] args) {
        try(
            // 1、创建一个文件字符输入流与源文件接通。
            Reader fr = new FileReader("day10-oop\\src\\csb.txt");
            // a、把低级的字符输入流包装成高级的缓冲字符输入流。
            BufferedReader br = new BufferedReader(fr); // 多态下调用子类方法,只能强转或不用多态
        ) {
            // 2、用循环,每次读取一行数据。 
            String line;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.2.2 字符缓冲输出流 BufferedWritter

字符缓冲输出流:BufferedWritter,可提高字符输出流写取数据的性能,除此之外多了换行功能

构造器:
在这里插入图片描述
独有方法:
在这里插入图片描述

注:特性是由原始管道决定。(如:若想追加数据,在原始管道中使用追加管道数据的构造方法)

示例:

public class BufferedWriterDemo3 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个字符输出流管道与目标文件接通
        // Writer fw = new FileWriter("day10-oop\\src\\data02.txt"); // 覆盖管道,每次启动都会清空文件之前的数据
        Writer fw = new FileWriter("day10-oop\\src\\data02.txt", true); // 追加数据
        BufferedWriter bw = new BufferedWriter(fw); // 特性是由原始管道决定,因此若想追加数据,也是设置上一行代码

        // a.public void write(int c):写一个字符出去
        bw.write(98);
        bw.write('a');
        bw.write('徐');
        bw.newLine(); // bw.write("\r\n"); // 换行

        // b.public void write(String c)写一个字符串出去
        bw.write("abc我是中国人");
        bw.newLine(); // bw.write("\r\n"); // 换行


        // c.public void write(char[] buffer):写一个字符数组出去
        char[] chars = "abc我是中国人".toCharArray();
        bw.write(chars);
        bw.newLine(); // bw.write("\r\n"); // 换行


        // d.public void write(String c ,int pos ,int len):写字符串的一部分出去
        bw.write("abc我是中国人", 0, 5);
        bw.newLine(); // bw.write("\r\n"); // 换行

        // e.public void write(char[] buffer ,int pos ,int len):写字符数组的一部分出去
        bw.write(chars, 3, 5);
        bw.newLine(); // bw.write("\r\n"); // 换行

        // fw.flush();// 刷新后流可以继续使用
        bw.close(); // 关闭包含刷新,关闭后流不能使用
    }
}

五、转换流

上文在使用字符流读取中文的时候,只有在文件和代码的编码一致才不会乱码,但编码不一致会出现乱码,而转换流可解决上述问题。

5.1 字符输入转换流 InputStreamReader

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

构造器:
在这里插入图片描述
示例:

public class InputStreamReaderDemo01 {
    public static void main(String[] args) throws Exception {
        // 1、提取GBK文件的原始字节流。
        InputStream is = new FileInputStream("day10-oop\\src\\dataGBK.txt");
        
        // 2、把原始字节流转换成字符输入流
        // Reader isr = new InputStreamReader(is); // 默认以UTF-8的方式转换成字符流。 还是会乱码的  跟直接使用FileReader是一样的
        Reader isr = new InputStreamReader(is , "GBK"); // 以指定的GBK编码转换成字符输入流  完美的解决了乱码问题

        // 3、把低级的字符输入流包装成高级的缓冲字符输入流。
        BufferedReader br = new BufferedReader(isr);

        String line;
        while ((line = br.readLine()) != null){
            System.out.println(line); // 正常打印
        }
    }
}

5.2 字符输出转换流 OutputStreamWrite

字符输出转换流:OutputStreamWriter,可以把字节输出流按照指定编码转换成字符输出流

构造器:
在这里插入图片描述

示例:

public class OutputStreamWriterDemo02 {
    public static void main(String[] args) throws Exception {
        // 1、定义一个字节输出流
        OutputStream os = new FileOutputStream("day10-oop\\src\\demoGBK.txt");

        // 2、把原始的字节输出流 转换成 字符输出流
        // Writer osw = new OutputStreamWriter(os); // 以默认的UTF-8写字符出去 跟直接写FileWriter一样
        Writer osw = new OutputStreamWriter(os , "GBK"); // 指定GBK的方式写字符出去

        // 3、把低级的字符输出流包装成高级的缓冲字符输出流。
        BufferedWriter bw = new BufferedWriter(osw);

        bw.write("我爱中国1~~");
        bw.write("我爱中国2~~");
        bw.write("我爱中国3~~");
        bw.close();
    }
}

六、序列化流

6.1 对象序列化与反序列化

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

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


6.2 对象字节输出流 ObjectOutputStream

构造器:
在这里插入图片描述

序列化方法:
在这里插入图片描述

注意:

① 序列化对象必须实现序列化接口。
② transient 修饰的成员变量不参与序列化。

示例:

public class Student implements Serializable {
    // 申明序列化的版本号码
    // 序列化的版本号与反序列化的版本号必须一致才不会出错!
    private static final long serialVersionUID = 1;
    private String name;
    private String loginName;
    // transient 修饰的成员变量不参与序列化了
    private transient String passWord;
    private int age ;
	...
}
public class ObjectOutputStreamDemo1 {
    public static void main(String[] args) throws Exception {
        // 1、创建学生对象
        Student s = new Student("张三", "zhangsan", "1314520", 21);

        // 2、对象序列化:使用对象字节输出流包装字节输出流管道
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day10-oop/src/obj.txt"));

        // 3、直接调用序列化方法
        oos.writeObject(s);

        // 4、释放资源
        oos.close();
        System.out.println("序列化完成了~~");
    }
}

6.3 对象字节输入流 ObjectInputStream

构造器:
在这里插入图片描述
序列化方法:
在这里插入图片描述

示例:

public class ObjectInputStreamDemo2 {
    public static void main(String[] args) throws Exception {
        // 1、创建对象字节输入流管道包装低级的字节输入流管道
        ObjectInputStream is = new ObjectInputStream(new FileInputStream("day10-oop/src/obj.txt"));

        // 2、调用对象字节输入流的反序列化方法
        Student stu = (Student) is.readObject();
        System.out.println(stu );
    }
}

七、打印流

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

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

7.1 PrintStream

构造器:
在这里插入图片描述
常用方法:
在这里插入图片描述


7.2 PrintWriter

构造器:
在这里插入图片描述

常用方法:
在这里插入图片描述

示例1:

public class PrintDemo1 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个打印流对象
        // PrintStream ps = new PrintStream(new FileOutputStream("day10-oop/src/print.txt"));
        PrintStream ps = new PrintStream(new FileOutputStream("day10-oop/src/print.txt" , true)); // 追加数据,在低级管道后面加True
        // PrintStream ps = new PrintStream("day10-oop/src/print.txt" );
        // PrintWriter pw = new PrintWriter("day10-oop/src/print.txt"); // 打印功能上与PrintStream的使用没有区别

        ps.println(97);
        ps.println('a');
        ps.println(23.3);
        ps.println(true);
        ps.println("我是打印流输出的,我是啥就打印啥");
        ps.close();
    }
}

示例2: 改变输出语句的位置

public class PrintDemo2 {
    public static void main(String[] args) throws Exception {
        System.out.println("锦瑟无端五十弦");
        System.out.println("一弦一柱思华年"); // out 是 PrintStream 对象

        // 改变输出语句的位置(重定向)
        PrintStream ps = new PrintStream("day10-oop/src/log.txt");
        System.setOut(ps); // 把系统打印流改成我们自己的打印流

        System.out.println("庄生晓梦迷蝴蝶");
        System.out.println("望帝春心托杜鹃");
    }
}

7.3 PrintStream 和 PrintWriter 的区别

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

补充:Commons-IO 框架

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

FileUtils 主要有如下方法:
在这里插入图片描述

示例:

/**
    包的功能描述见下表:
         | 包                                  | 功能描述                                     |
         | ----------------------------------- | :------------------------------------------- |
         | org.apache.commons.io               | 有关Streams、Readers、Writers、Files的工具类 |
         | org.apache.commons.io.input         | 输入流相关的实现类,包含Reader和InputStream  |
         | org.apache.commons.io.output        | 输出流相关的实现类,包含Writer和OutputStream |
         | org.apache.commons.io.serialization | 序列化相关的类

    步骤:
         1. 下载commons-io相关jar包;http://commons.apache.org/proper/commons-io/
         2. 把commons-io-2.6.jar包复制到指定的Module的lib目录中
         3. 将commons-io-2.6.jar加入到classpath中

    小结:
         IOUtils和FileUtils可以方便的复制文件和文件夹!!
 */
public class CommonsIODemo {
    public static void main(String[] args) throws Exception {

        // 1.完成文件复制!
        IOUtils.copy(new FileInputStream("D:\\resources\\hushui.jpeg"),
                new FileOutputStream("D:\\resources\\hushui2.jpeg"));

        // 2.完成文件复制到某个文件夹下!
        FileUtils.copyFileToDirectory(new File("D:\\resources\\hushui.jpeg"), new File("D:/"));


        // 3.完成文件夹复制到某个文件夹下!
        FileUtils.copyDirectoryToDirectory(new File("D:\\resources") , new File("D:\\new"));
        FileUtils.deleteDirectory(new File("D:\\new"));

        // JDK1.7 也做了一些一行代码完成复制的操作:New IO的技术
        // Files.copy(Path.of("D:\\resources\\hushui.jpeg"), Path.of("D:\\resources\\hushui3.jpeg"));

        FileUtils.deleteDirectory(new File("D:\\new")); // 只能删除空文件夹
    }
}

文章参考:Java入门基础视频教程,java零基础自学就选黑马程序员Java入门教程(含Java项目和Java真题)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI绘画:Midjourney 注册

AI绘画:Midjourney 注册 前提:需要魔法才能使用 第一步:下载Discord 官方网站:https://discord.com/,打开网址,下载您需要的版本。 注意:支持手机端(Android&ios),Windows,Linux,Mac 下面以Windows注册为例<

纵使AI再强悍,低代码风韵犹存

互联网沉默已久&#xff0c;ChatGPT的出现激起千层浪&#xff0c;沉寂已久的互联网迎来新一轮的机遇。毫不夸张地说&#xff0c;任何一家以技术见长的企业&#xff0c;人工智能绝对占有一席之地。 目录 人工智能很强悍 低代码风韵犹存 快速开发平台&#xff0c;大有看头 AI…

网络安全等级保护等级保护对象的安全保护等级

什么是等保&#xff1f; 2017年6月1号&#xff0c;《中华人民共和国网络安全法》出台&#xff0c;国家实行等级安全保护制度。网络安全等级保护以《中华人民共和国网络安全法》为法律依据&#xff0c;以2019年5月发布的《GB/T22239-2019 信息安全技术 网络安全等级保护基本要求…

网络安全难学吗?前途怎么样?

网络安全是一门技术性很强的学科&#xff0c;需要掌握扎实的计算机技术基础和相关的安全技能&#xff0c;因此对于初学者来说可能会比较困难。但是&#xff0c;网络安全是一个非常重要的领域&#xff0c;在如今数字化的时代&#xff0c;各种网络犯罪、信息泄露等安全问题屡见不…

javassist动态生成,修改字节码 demo

Javassist 是一个开源的分析、编辑和创建 Java 字节码的类库&#xff0c;被广泛用于程序性的类文件操作和运行时 AOP 框架&#xff0c;能动态改变类的结构&#xff0c;或者动态生成类。 关于javassist和反射 Javassist 不是通过反射来实现的&#xff0c;而是通过直接操作字节…

python3+telnetlib实现简单自动测试

1 telnetlib介绍 1.1 简介 官方介绍文档&#xff1a;telnetlib – Telnet 客户端 — Python 3.9.6 文档 telnetlib 模块提供一个实现Telnet协议的类 Telnet。 1.2 库常用函数及使用 1.2.1 建立连接 建立连接有两种方式&#xff1a;1、实例化函数的时候&#xff0c;将可选参数…

PSP - AlphaFold2 Multimer 的 Heteromer (异源多聚体) MSA 逻辑

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/130733737 同源多聚体 (Homomer) 是由相同的蛋白质亚基组成的,而异源多聚体 (Heteromer) 是由不同的蛋白质亚基组成的。同源多聚体的亚基之间通常有对称的相…

网络安全真的有那么好吗

网络安全是一个永远不会完美的领域&#xff0c;因为网络空间是一个开放、动态、复杂的环境&#xff0c;存在着许多安全威胁和攻击手段。虽然现代的安全技术和防御措施已经很强大&#xff0c;但黑客和病毒等攻击手段也在不断升级&#xff0c;不断打破现有的安全防御措施。因此&a…

论-如何更好的帮助小伙伴们写出更多高质量的论文

开篇一张图&#xff0c;告诉大家&#xff0c;哥哥我身体依然倍棒&#xff0c;依然奋战在一线。 前言 最近几个月一直在加班为小伙伴们创造价值&#xff0c;已经帮助上百位小伙伴解决了论文的“烦恼”与“忧愁”&#xff0c;但是我想说的是&#xff0c;哥哥真的苦啊&#xff0c;…

【分布族谱】泊松分布和二项分布、正态分布的关系

文章目录 泊松分布和二项分布的关系和正态分布的关系 泊松分布 如果在有限时间 ( 0 , 1 ) (0,1) (0,1)内进行 n n n次伯努利实验&#xff0c;那么每次伯努利实验所占用的时间为 1 n \frac{1}{n} n1​&#xff0c;按照自然规律&#xff0c;一件事情肯定是时间越长越容易发生&am…

chatgpt赋能Python-pycharm改名字

PyCharm更名为JetBrains PyCharm——专属Python开发者的最佳IDE JetBrains PyCharm是一款Python开发者最喜欢使用的IDE之一。然而&#xff0c;在2021年初&#xff0c;这款世界著名的Python IDE进行了一次重大更名——PyCharm更名为JetBrains PyCharm。在这篇文章中&#xff0c…

Rust每日一练(Leetday0003) 整数反转、字串转整数、回文数

目录 7. 整数反转 Reverse Integer &#x1f31f;&#x1f31f; 8. 字符串转换整数 String-to-integer (atoi) &#x1f31f;&#x1f31f; 9. 回文数 Palindrome Number &#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一…

chatgpt赋能Python-pycharm提取数据

PyCharm提取数据指南 PyCharm作为一款强大的Python IDE&#xff0c;在数据科学和数据分析领域广受欢迎。它不仅可以用于Python代码开发&#xff0c;还能够提高数据的处理效率。本文将介绍如何在PyCharm中使用Python代码提取数据&#xff0c;以及探讨如何最大化地发挥其数据处理…

chatgpt赋能Python-pycharm行数

PyCharm行数&#xff1a;如何轻松管理您的代码库 作为一个有10年Python编程经验的工程师&#xff0c;我知道管理庞大代码库的挑战。在这种情况下&#xff0c;行数管理是一个非常重要的方面。幸运的是&#xff0c;有很多现代的集成开发环境&#xff08;IDE&#xff09;可以帮助…

chatgpt赋能Python-pycharm粘贴把空格识别成行

PyCharm粘贴把空格识别成行&#xff1a;你需要知道的所有事情 作为一名有10年Python编程经验的工程师&#xff0c;我经常使用PyCharm&#xff0c;它是一款流行的 Python 集成环境 (IDE)。今天&#xff0c;我想分享一些有关 PyCharm 粘贴把空格识别成行的信息。 什么是PyCharm…

Windows活动目录以及部分Windows网络应用服务器

一.本地用户和组 Windows Server2008本地用户与组: 用户:就是包含用户名、密码、权限以及说明。 用户组:具有相同性质的用户归结在一起&#xff0c;统一授权&#xff0c;组成用户组。 用户组分类:全局组、本地组、特殊组。 各组名及其权限&#xff1a; Administrators&#…

不用等待列表,马上解锁New Bing GPT-4功能

大家好&#xff0c;我是可夫小子&#xff0c;关注AIGC、读书和自媒体。解锁更多ChatGPT、AI绘画玩法。加&#xff1a;keeepdance&#xff0c;备注&#xff1a;chatgpt&#xff0c;拉你进群。 今年1月份&#xff0c;微软投资OpenAI 100亿之后&#xff0c;就迅速把ChatGPT的能力接…

chatgpt赋能Python-pycharm添加numpy库

PyCharm添加Numpy库 PyCharm是一款功能强大的Python集成开发环境&#xff0c;广泛应用于Python程序开发和数据分析领域。Numpy是Python中著名的科学计算库&#xff0c;包括数组、矩阵、数学函数等模块&#xff0c;是数据科学领域中不可或缺的工具。 本篇SEO文章将介绍如何在P…

Android之 Activity活动详解

一 四大组件 1.1 Activity组件&#xff0c;它一个单独的窗口&#xff0c;程序流程都必须在Activity中运行。 1.2 service组件&#xff0c;用于在后台完成用户指定的操作。 1.3 content provider组件&#xff0c;会为所有的应用准备一个内容窗口&#xff0c;并且保留数据库、…

《程序员面试金典(第6版)》面试题 16.24. 数对和(哈希映射,双指针)

题目描述 设计一个算法&#xff0c;找出数组中两数之和为指定值的所有整数对。一个数只能属于一个数对。 题目传送门 示例 1: 输入: nums [5,6,5], target 11 输出: [[5,6]]示例 2: 输入: nums [5,6,5,6], target 11 输出: [[5,6],[5,6]]提示&#xff1a; nums.length &…