Java:缓冲流、转换流、序列化流

本文详细介绍了Java中的缓冲流,包括字节缓冲流和字符缓冲流的使用,以及如何通过缓冲流进行文本排序的实践。转换流部分讲解了字符编码和字符集,以及转换流在不同编码之间的转换作用。序列化流部分则阐述了对象序列化和反序列化的概念,以及transient关键字在序列化中的应用。文章旨在帮助读者深入理解Java I/O流的高级特性和实践操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、缓冲流-概述

读、写都可以使用一种“数组”的方式,这种方式会大大提高读、写的效率,基于这种原因,Java内部提供一种“缓冲流”,其内部自带一个缓冲区(数组),目的也是为了提高程序运行速率。

2、缓冲流-字节缓冲流

1)、输出流:BufferedOutputStream

2)、输入流:BuferedInputStream

注意:都没有特有的方法,都是继承于父类的方法

public static void main(String[] args) {

    try (
            //1.源文件到程序的输入流:
            BufferedInputStream bufIn = new BufferedInputStream(
					new FileInputStream("d:\\douyu.exe"));
            //2.程序到目标文件的:输出流
            BufferedOutputStream bufOut = new BufferedOutputStream(
					new FileOutputStream("e:\\douyu_copy.exe"))
    ) {
        //一次读写一个字节
        /*
        int b = 0;
        while ((b = bufIn.read()) != -1) {//从"缓存区读",一次读一个字节
            bufOut.write(b);//输出到"缓存区",一次输出一个字节
        }
        */
        //一次读写一个字节数组
        byte[] byteArray = new byte[1024];
        int len = 0;
        while ((len = bufIn.read(byteArray)) != -1) {//从"缓存区读",一次读1K
            bufOut.write(byteArray,0,len);//输出到”缓存区",一次输出1k
        }

        System.out.println("复制完毕!");
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

在这里插入图片描述

3、缓冲流-字符缓冲流

1)、字符缓冲流同“字节缓冲流”作用一样,内部提供了8K的缓冲区;

2)、字符缓冲流的俩个类各自提供了一个特有的方法:

输出流:newLine();//换行

输入流:readLine();//忽略换行

配套使用

public static void main(String[] args) {
    try (BufferedReader bufIn = new BufferedReader(
				new FileReader("demo03.txt"));
         BufferedWriter bufOut = new BufferedWriter(
				new FileWriter(("demo3_copy2.txt")))
    ) {

        //一次读写一个字符数组
        /*char[] chArray = new char[1024];
        int len = 0;
        while ((len = bufIn.read(chArray)) != -1) {
            bufOut.write(chArray,0,len);
        }*/

        //使用特有方法赋值
        String row = null;
        while ((row = bufIn.readLine()) != null) {//一次读取一行
            bufOut.write(row);
            bufOut.newLine();//输出一个换行
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

4、缓冲流-练习-文本排序-分析

在这里插入图片描述

5、缓冲流-练习-文本排序-实现

public static void main(String[] args) throws IOException {
    //1.源文件的输入流
    BufferedReader bufIn = new BufferedReader(new FileReader("demo05.txt"));
    //2.目标文件的输出流
    BufferedWriter bufOut = new BufferedWriter(new FileWriter("demo05_copy.txt"));

    //3.一次读一行,存储到Map中
    Map<Integer, String> map = new HashMap<>();
    String row = null;
    while ((row = bufIn.readLine()) != null) {//row = "3.侍中、 侍郎郭攸之、 费祎..."
        String id = row.substring(0, row.indexOf("."));//String id = "3"
        String msg = row.substring(row.indexOf(".") + 1);//String msg = "侍中、 侍郎郭攸之、...."

        map.put(Integer.valueOf(id), msg);//map.put(3,"侍中、 侍郎郭攸之、....")
    }

    //4.向目标文件写入
    for (int i = 1; i <= map.size(); i++) {
        bufOut.write(i + "." + map.get(i));
        bufOut.newLine();
    }
    //5.关闭文件
    bufOut.close();
    bufIn.close();
    System.out.println("处理完毕!");
}

6、转换流-为甚要有字符流

1)、字符流:一次按一个字符读取,每个国家的字符占用的字节数是不同的,(UTF-8,汉字占用3个字节)

2)、各个国家使用的编码表不同,字符占用的字节数也就不同,如果都使用“字节流”读写就会很不方便,所以Java提供了一种专门操作纯文本文件的字符流

3)、可以根据各国的语言编码方式,来自动对字符进行编码、解码

7、转换流-字符编码和字符集

常见字符集(编码表):记录了字符与数字的映射关系。计算机村存储字符时就是存储的对应是数字的二进制数

1)、ASCII码表:最早的码表,记录了128个字符,每个字符使用1个字节表示。

2)、中文码表(GBxxxx)

GB2312:最早的中文码表,记录7000多字符,现在不在使用了

GBK:目前使用的码表,记录2w多汉字,每个汉字使用2个字节表示

UTF-8码表:国际码表。有中文;字符采用1,2,3,4字节表示。每个中文使用:3个字节表示;

8、转换流-编码引出的问题

乱码–>解码与编码不一致:

例:文本中是GBK编码,而读取时IDEA使用的是UTF-8编码

public static void main(String[] args) throws IOException {
    FileReader in = new FileReader("demo06.txt");//使用UTF-8解码
    int c = 0;
    while ((c = in.read()) != -1) {
        System.out.println("读取的字符:" + (char)c);//乱码
    }
    in.close();
}
//原因:文本中是:GBK编码
//读取时,使用UTF-8解码;

9、转换流-转换输出流OutputStreamWriter的使用

1)、FileWriter和FileReader都是使用默认的编码方式

2)、使用OutputSreamWriter可以指定编码方式

public static void main(String[] args) throws IOException {
    OutputStreamWriter osw = new OutputStreamWriter(
                                new FileOutputStream("demo07.txt"), "GBK");
    osw.write("你好");//使用GBK编码:两个汉字:4个字节

    osw.close();
}

10、转换流-转换输入流InputStreamReader的使用

使用InputStreamReader可以指定解码方式

public static void main(String[] args) throws IOException {
    InputStreamReader isr = new InputStreamReader(
                            new FileInputStream("demo07.txt"), "GBK");
    int c = isr.read();//按照GBK解码:一次读取2个字节
    System.out.println("读取的字符:" + (char)c);
    isr.close();
}

11、转换流-转换流工作方式图解

在这里插入图片描述

12、转换流-练习-转换文件编码

将一个使用GBK编码的文档复制为一个UTF-8编码的文档

public static void main(String[] args) throws IOException {
    //1.将demo09.txt(GBK-8字节)复制为:demo09_UTF8.txt(12个字节)
    //2.使用GBK读取
    InputStreamReader isr = new InputStreamReader(
                            new FileInputStream("demo09.txt"), "GBK");
    //使用UTF-8输出
    OutputStreamWriter osw = new OutputStreamWriter(
                            new FileOutputStream("demo09_UTF8.txt"),"UTF-8"
    );
    //3.循环读取
    int c = 0;
    while ((c = isr.read()) != -1) {
        osw.write(c);
    }

    //4.关闭流
    osw.close();
    isr.close();
}

13、序列化-概述

1)、序列化:指将一个对象连同属性值一起存储在一个文件中,或者通过网络传输,这个过程叫做序列化

2)、反序列化:将之前已经序列化的对象,再次读取到程序中,并在内存中创建对象

14、序列化-序列化流ObjectOutputStream类

public class Student implements Serializable{//要想序列化,必须实现Serializable接口,进而获得一些功能(可以被序列化的功能)
    String name;
    int age;

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

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

测试类:

public static void main(String[] args) throws IOException {
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("demo10.txt"));
    Student stu = new Student("张三", 18); 
    oos.writeObject(stu);
    oos.close();
}

注意:被序列化的对象必须实现:Serializable(接口),

此接口无任何抽象方法,这种接口叫:标记接口,表示为实现它的类开启某些功能

15、序列化-反序列化ObjectInputStream类

public static void main(String[] args) 
			throws IOException, ClassNotFoundException {
    //反序列化
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("demo10.txt"));
    Object obj = ois.readObject();//在内存产生的是Student对象
    Student stu = (Student)obj;//向下转型
    System.out.println(stu);
}

注意:反序列化时,接收的对象必须要是在序列化时的包下的那个对象类,否则运行异常

16、序列化-关于版本号

public class Student implements Serializable{
    String name;
    int age;
    String sex;
    private static final long serialVersionUID = 2;
    ....
}

注意:反序列化之前会检查现有类的序列号和文件中对象的序列号是否相同,不同将产生异常,建议在开发中自己对序列号进行维护

17、序列化-禁止属性被序列化transient关键字

public class Student implements Serializable{
    String name;
    int age;
    transient String sex;
	...
}

在属性前加transient,该属性将不会被序列化

18、序列化-练习-序列化集合

public static void main(String[] args) 
			throws IOException, ClassNotFoundException {
    /*//1.先存储一些Student对象
    ArrayList<Student> stuList = new ArrayList<>();
    stuList.add(new Student(1, "特朗普", 16));
    stuList.add(new Student(2, "金三胖", 18));
    stuList.add(new Student(3, "普京", 19));

    //将集合中数据全部序列化到文件中
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("demo12.txt"));
    oos.writeObject(stuList);
    oos.close();

    System.out.println("序列化结束");*/

    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("demo12.txt"));
    Object obj = ois.readObject();
    ois.close();
    
    ArrayList<Student> stuList = (ArrayList<Student>)obj;
    for (Student stu : stuList) {
        System.out.println(stu);
    }
}

19、打印流-概述

java中有两种打印流:

1)、字节打印流:PrinteStream

2)、字符打印流:printWrite

打印流的特点:

1)、只有输出流,没有输入流;

2)、可以操作控制台,也可以操作文件;

20、打印流-字节打印流PrintStream类

1)、System.out.println():向控制台输出数据

2)、System.out就是PrintStream类型:默认被指向:控制台

3)、可以将out的流向进行更改,使其流向文件:

public static void main(String[] args) throws FileNotFoundException {

    PrintStream ps = new PrintStream("demo13.txt");
    System.setOut(ps);

    System.out.println("Hello");
    System.out.println("呵呵");
    System.out.println("嘻嘻");
}

复习

  • 能够使用字节缓冲流读取数据到程序

    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("文件位置"));
    Byte[] byt = new Byte[1024];
    int len = 0;
    while((len = bis.read(byt)) != -1){
        System.out.println(byt);
    }
    
  • 能够使用字节缓冲流写出数据到文件

    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("文件位置"));
    bos.write("文件内容".getByte());
    
  • 能够明确字符缓冲流的作用和基本用法

    BufferedReader reader = new BufferedReader(new FileInputStream("文件位置"));
    BufferedWrite write = new BufferWrite(new FileOutputStream("文件位置"));
    byte[] byt = new byte[1024];
    int len = 0;
    while((len = reader.read(byte))!=-1){
        writer.write(byte,0,len);
    }
    reader.close();
    write.close();
    
  • 能够使用缓冲流的特殊功能

    readLine();//读取一行字符
    newLine();//换行
    //一般配套使用
    
  • 能够阐述编码表的意义

    编码表就是记录有字符与其相对应的数字,计算机存储这些字符时都会将这些字符转换为与其对应的二进制进行存储

  • 能够使用转换流读取指定编码的文本文件

    InputStreamReader in = new InputStreamReader(new FileInputStream("文件位置"),"GBK");
    OutputStreamWriter out = new OutputStreamWrite(new FileOutputStream("文件位置"),"UTF-8");
    int c = 0;
    while((c = in.read())!=-1){
        out.write(c);
    }
    in.close();
    out.close();
    
  • 能够使用转换流写入指定编码的文本文件

  • 能够说出打印流的特点

    只有输出流,没有输入流,可以输出到控制台,也可以输出到文件中;默认为控制台

    PrintStream ps = new PrintStream("文件位置");
    System.setOut(ps);
    System.out.println("要写入的内容");
    
  • 能够使用序列化流写出对象到文件

    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("复制目标文件"));
    Student stu = new Student(1,"张珊",23);
    oos.writeObject(stu);
    oos.close();
    
  • 能够使用反序列化流读取文件到程序中

    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("目标文件"));
    Object obj = ois.readObject();
    Student student = (Student)obj;
    System.out.println(student);
    ois.close();
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值