【Java IO流】缓冲流和对象流的解析和应用实例

目录

前言

一、缓冲流

四种方式拷贝文件的用时对比

二、对象流

1. 使用对象流写入对象到本地文件

2. 使用对象流读取对象数据

总结


前言

【File文件管理及IO流(基本流)】icon-default.png?t=N7T8http://t.csdnimg.cn/uG5Ff 该篇博客中,介绍了学习高级流需要的前置知识:

  1. 文件管理
  2. 基本的输入输出流:了解基本的输入输出流的概念和使用方法,包括字节流和字符流,以及如何读写文件或处理其他数据源

Java 中的高级流指的是建立在基本字节流或字符流之上的流,它们提供了更高级别的功能以简化 I/O 操作。除缓冲流和对象流外,常见的高级流还有:数据流、打印流、压缩流、转换流等。


一、缓冲流

缓冲流(Buffered Streams)在 Java 中是一种用于提高输入输出效率的流。它们通过在内存中创建缓冲区来减少对底层资源(如文件、网络连接)的频繁访问,从而提高读写数据的性能。

常见的缓冲流包括:

  • BufferedInputStream(字节缓冲输入流)
  • BufferedOutputStream(字节缓冲输出流)
  • BufferedReader(字符缓冲输入流)
  • BufferedWriter(字符缓冲输出流)

它们构造方法的参数都是对应的基本流,例如:

public BufferedInputStream(InputStream is)

缓冲流的原理:底层自带了长度为8192的缓冲区提高性能。

缓冲中的两个独有方法(非常实用):

1.readLine() 读取一行
用于从输入流中读取一行文本数据,并返回一个字符串表示该行数据。这个方法通常用于读取文本文件中的内容,逐行读取文本信息。2.newLine() 通用换行
作用是写入一个平台无关的行分隔符,即换行符。
使用 newLine()方法可以根据当前平台自动生成正确的换行符,而不需要手动编写特定的换行符。
通常情况下,不同操作系统的行分隔符如下:(1)Windows 系统使用回车符和换行符表示行尾,即\r\n(2)Unix 和类 Unix 系统(如 Linux)使用换行符表示行尾,即 \n。(3)旧版 Mac OS 使用回车符表示行尾,即 \r。 

为方便读取文本文件,这里用字符缓冲流进行示例(需要创建好对应的文件,路径也要正确):

import java.io.*;public class CharacterBS {  //字符缓冲流public static void main(String[] args) throws IOException {//读取数据(输入流)BufferedReader br = new BufferedReader(new FileReader("File\\buffer.txt"));//两个独有方法:readLine() 读取一行//            newLine() 通用换行String s;while ((s = br.readLine()) != null) {System.out.println(s);}br.close();//写数据(输出流)BufferedWriter bw = new BufferedWriter(new FileWriter("File\\buffer2.txt"));bw.write("缓冲流(Buffered Streams)");bw.newLine();bw.write("BufferedReader:提供缓冲读取文本数据的功能。");bw.newLine();bw.write("BufferedWriter:提供缓冲写入文本数据的功能。");bw.newLine();bw.close();}
}

读取的数据:

写入的数据: 

四种方式拷贝文件的用时对比

拷贝文件四种方式拷贝文件(边读边写),并统计各自用时(这里的文件越大越好,太小体现不出差别)1.字节流的基本流:一次读写一个字节2.字节流的基本流:一次读写一个字节数组[8192]3.字节缓冲流:一次读写一个字节4.字节缓冲流:一次读写一个字节数组[8192]
import java.io.*;public class Test1 {public static void main(String[] args) throws IOException {/*拷贝文件四种方式拷贝文件,并统计各自用时字节流的基本流:一次读写一个字节字节流的基本流:一次读写一个字节数组字节缓冲流:一次读写一个字节字节缓冲流:一次读写一个字节数组*/long time1 = method1();long time2 = method2();long time3 = method3();long time4 = method4();System.out.println(time1);System.out.println(time2);System.out.println(time3);System.out.println(time4);}private static long method1() throws IOException {long start = System.currentTimeMillis();FileInputStream fis = new FileInputStream("File\\read.txt");FileOutputStream fos = new FileOutputStream("File\\write.txt");int b;while ((b = fis.read()) != -1) {fos.write(b);}fos.close();fis.close();long end = System.currentTimeMillis();return end - start;}private static long method2() throws IOException {long start = System.currentTimeMillis();FileInputStream fis = new FileInputStream("File\\read.txt");FileOutputStream fos = new FileOutputStream("File\\write.txt");byte[] bytes = new byte[8192];int len;while ((len = fis.read(bytes)) != -1) {fos.write(bytes, 0, len);}fos.close();fis.close();long end = System.currentTimeMillis();return end - start;}private static long method3() throws IOException {long start = System.currentTimeMillis();BufferedInputStream bis = new BufferedInputStream(new FileInputStream("File\\read.txt"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("File\\write.txt"));int b;while ((b = bis.read()) != -1) {bos.write(b);}bos.close();bis.close();long end = System.currentTimeMillis();return end - start;}private static long method4() throws IOException {long start = System.currentTimeMillis();BufferedInputStream bis = new BufferedInputStream(new FileInputStream("File\\read.txt"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("File\\write.txt"));byte[] bytes = new byte[8192];int len;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}bos.close();bis.close();long end = System.currentTimeMillis();return end - start;}
}

对比结果(文件太小了所以读写字节数组的差距没有体现): 

  1. 字节流的基本流:一次读写一个字节
  2. 字节流的基本流:一次读写一个字节数组[8192]
  3. 字节缓冲流:一次读写一个字节
  4. 字节缓冲流:一次读写一个字节数组[8192]

二、对象流

对象流(Object Streams)也叫序列化/反序列化流,是 Java 中用于读写对象的流。对象流可以将对象以二进制形式序列化(Serialization)后写入输出流,也可以从输入流中读取二进制数据并反序列化(Deserialization)为对象。

Java 提供了两个主要的对象流类:

  1. ObjectOutputStream:用于将对象序列化后写入输出流。
  2. ObjectInputStream:用于从输入流中读取二进制数据并反序列化为对象。

同缓冲流,它们构造方法的参数也是基本流:

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("objects.bin"));
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("objects.bin"));

需要注意的是,要使对象能够被序列化,该对象所属的类必须实现 Serializable 接口。序列化过程会将对象转换成字节序列,因此对象的字段和类的结构都需要支持序列化。

对象流的使用场景包括但不限于:保存和加载对象数据(因为写入到文件后是一对看不懂的数据)、对象的网络传输等。

作用:通过对象流,我们可以方便地将对象以二进制形式写入到输出流中,并从输入流中读取并还原为对象,实现了对象的持久化和简化了数据传输。写入到文件后

细节:要写出的对象必须实现Serializable接口(标记性接口) + serialVersionUID(版本号)否则会抛出NotSerializableException异常

写入对象的方法:writeObject(对象);

读取对象的方法:readObject(); 返回值:Object

1. 使用对象流写入对象到本地文件

写入对象前的准备工作,自定义类:

import java.io.Serial;
import java.io.Serializable;public class Student implements Serializable {@Serialprivate static final long serialVersionUID = -3931917465211028662L;private String name;private int age;//transient: 瞬态关键字//作用:不会把当前属性序列化到本地文件当中private transient String address;public Student() {}public Student(String name, int age, String address) {this.name = name;this.age = age;this.address = address;}/*** 获取** @return name*/public String getName() {return name;}/*** 设置** @param name*/public void setName(String name) {this.name = name;}/*** 获取** @return age*/public int getAge() {return age;}/*** 设置** @param age*/public void setAge(int age) {this.age = age;}/*** 获取** @return address*/public String getAddress() {return address;}/*** 设置** @param address*/public void setAddress(String address) {this.address = address;}public String toString() {return "Student{name = " + name + ", age = " + age + ", address = " + address + "}";}
}
import java.io.Serial;
import java.io.Serializable;public class Teacher implements Serializable {@Serialprivate static final long serialVersionUID = 2983184546427358899L;private String name;private int age;private String address;public Teacher() {}public Teacher(String name, int age, String address) {this.name = name;this.age = age;this.address = address;}/*** 获取** @return name*/public String getName() {return name;}/*** 设置** @param name*/public void setName(String name) {this.name = name;}/*** 获取** @return age*/public int getAge() {return age;}/*** 设置** @param age*/public void setAge(int age) {this.age = age;}/*** 获取** @return address*/public String getAddress() {return address;}/*** 设置** @param address*/public void setAddress(String address) {this.address = address;}public String toString() {return "Teacher{name = " + name + ", age = " + age + ", address = " + address + "}";}
}

写入一个对象: 

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;public class Test1 {    //序列化流/对象操作输出流public static void main(String[] args) throws IOException {/*需求:利用序列化流/对象操作输出流,把一个对象写到本地文件中细节:要写出的对象必须实现Serializable接口(标记性接口) + serialVersionUID(版本号)否则回抛出NotSerializableException异常transient: 瞬态关键字作用:不会把当前属性序列化到本地文件当中*///1.创建对象Student stu = new Student("张三", 23, "厦门");//2.创建续流化流/对象操作输出流对象ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("File\\object.txt"));//3.写出对象oos.writeObject(stu);//4.关流oos.close();}
}

写入后的数据: 

写入多个对象:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;public class Test_1 {public static void main(String[] args) throws IOException {/*用对象流读写多个对象需求:将多个自定义对象序列化到文件中,但是由于对象的个数不确定,反序列流该如何读取?*///序列化多个对象//1.创建对象Teacher t1 = new Teacher("张三", 23, "北京");Teacher t2 = new Teacher("李四", 24, "上海");Teacher t3 = new Teacher("王五", 25, "深圳");//2.将对象添加到集合中ArrayList<Teacher> list = new ArrayList<>();list.add(t1);list.add(t2);list.add(t3);//3.序列化集合ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("File\\teacher.txt"));oos.writeObject(list);//4.关流oos.close();}
}

2. 使用对象流读取对象数据

读取单个对象:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;public class Test2 {    //反序列化流/对象操作输入流public static void main(String[] args) throws IOException, ClassNotFoundException {//1.创建反序列化流/对象操作输入流ObjectInputStream ois = new ObjectInputStream(new FileInputStream("File\\object.txt"));//2.读取数据Object o = ois.readObject();//3.打印对象System.out.println(o);//4.释放资源ois.close();}
}

运行结果:

读取多个对象:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;public class Test_2 {public static void main(String[] args) throws IOException, ClassNotFoundException {//1.创建反序列化流的对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("File\\teacher.txt"));//2.读取数据ArrayList<Teacher> o = (ArrayList<Teacher>) ois.readObject();//System.out.println(o);for (Teacher teacher : o) {System.out.println(teacher);}//3.关流ois.close();}
}

运行结果: 


总结

当涉及到 Java I/O 操作时,缓冲流和对象流是两种非常常用的高级流。

缓冲流的功能:

  1. 提供了缓冲区功能,可以减少对底层数据源的直接访问次数,从而提高读写效率。
  2. 适用于对大量数据进行读写操作。

缓冲流的优点

  1. 提高了I/O操作的性能,减少了与底层数据源的交互次数。
  2. 提供了逐行读取文本数据的功能,方便文本处理操作。

对象流的功能:

  1. 用于将对象序列化成字节流或反序列化为对象。
  2. 可以实现对象的持久化、网络传输和跨平台数据交换等功能。

对象流的优点:

  1. 方便实现对象的保存和加载,简化了对象的序列化和反序列化过程。
  2. 可以实现对象在不同系统之间的传输和共享。

综上所述,缓冲流适用于提高读写效率和处理大量数据,而对象流则适用于处理对象的序列化和反序列化,方便实现对象数据的持久化和传输。根据具体需求,可以选择合适的流来进行数据操作。

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

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

相关文章

C++ 函数的默认形参和函数重载

C 函数的默认形参和函数重载 函数的默认形参 在C中&#xff0c;函数的默认形参&#xff08;Default Arguments&#xff09;允许在函数声明或定义时为一个或多个参数指定默认值。这意味着在调用函数时&#xff0c;如果某个参数没有提供值&#xff0c;则自动使用其默认值。这个…

字节跳动后端工程师实习生笔试题-c++

字节跳动后端工程师实习生笔试题链接 笔试题 1. 最大映射2. 木棒拼图3. 魔法权值4. 或与加 1. 最大映射 有 n 个字符串&#xff0c;每个字符串都是由 A-J 的大写字符构成。现在你将每个字符映射为一个 0-9 的数字&#xff0c;不同字符映射为不同的数字。这样每个字符串就可以看…

金航标和萨科微总经理宋仕强说,中国还有一个优势就是有全世界最大的半导体消费市场

金航标和萨科微总经理宋仕强说&#xff0c;中国还有一个优势就是有全世界最大的半导体消费市场&#xff0c;有超过1万亿人民币的规模&#xff0c;全球占比34%&#xff0c;领先美国&#xff08;27%&#xff09;&#xff0c;更大幅领先欧洲和日韩&#xff0c;金航标电子是在的中国…

Vue3 watch侦听器

一 侦听响应式ref 侦听响应式ref常量&#xff0c;当常量的ref的value值发生改变时会触发watch 一个小栗子&#xff1a;当输入框的输入内容变化时下方的文本也会跟着改变 <template><div class"box content"><div class"intro"><el…

【C语言】字符分类函数与字符转换函数

1. 字符分类函数 C语言中有⼀系列的函数是专门做字符分类的&#xff0c;也就是⼀个字符是属于什么类型的字符的。 这些函数的使用都需要包含⼀个头文件是 ctype.h 这些函数的使用方法非常类似&#xff0c;我们就讲解⼀个函数的事情&#xff1a; int islower ( int c ); islow…

Linux 15个常用脚本练习(初级)

&#xff08;1&#xff09;用户猜数字 #!/bin/bash # 脚本生成一个 100 以内的随机数,提示用户猜数字,根据用户的输入,提示用户猜对了, # 猜小了或猜大了,直至用户猜对脚本结束。 # RANDOM 为系统自带的系统变量,值为 0‐32767的随机数 # 使用取余算法将随机数变为 1‐100 的…

js中函数参数的归一化处理

在 JavaScript 中&#xff0c;函数参数的归一化处理是一种将不同类型或格式的参数转换为统一的标准或格式的过程。这样做的目的是为了提高代码的灵活性、可维护性和可重用性。 以下是一些常见的函数参数归一化处理的方式&#xff1a; 数据类型转换&#xff1a;将不同类型的参数…

软考高级,高项和架构哪个更容易?

软考高级共有5个科目&#xff0c;考试难度都是偏大的。相对而言&#xff0c;信息系统项目管理师的考试难度小于系统架构设计师&#xff0c;不过目前高项是1年1考&#xff0c;架构是1年2考&#xff0c;从这个层面来说&#xff0c;通过架构考试的机会要多一些。 架构&高项考…

RabbitMq——direct交换器和fanout交换器 扇形交换器

direct交换器&#xff1a; Configuration 发送 Bean protected Queue queue&#xff08;&#xff09;{ Queue queue new Queue&#xff08;“myQueue”&#xff09; return queue&#xff1b; } amqpTemplate.convertAndSend("myQueue","这是发送的内…

pytorch_fid计算fid

pip install pytorch-fid from pytorch_fid import fid_score# 准备真实数据分布和生成模型的图像数据 real_images_folder xxx generated_images_folder xxx# 计算FID距离值 fid_value fid_score.calculate_fid_given_paths([real_images_folder, generated_images_folder]…

【测试开发】自动化测试 selenium 篇

目录 一. 什么是自动化测试 二. selenium 1. selenium的工作原理 2. seleniumJava的环境搭建(Chrome浏览器) 三. selenium中常用的API 1. 定位元素 findElement 1.1 css选择语法 1.2 xpath 2. 操作测试对象 2.1 sendKeys-在对象上模拟按键输入 2.2 click-点击对象…

mmap访问内存方式

mmap访问内存方式 请看下面的Java代码&#xff0c;这段程序是取自1brc竞赛的第一名的代码。 public static void main(String[] args) throws IOException, InterruptedException {... ...try (var fileChannel FileChannel.open(java.nio.file.Path.of(FILE), java.nio.fil…

elasticsearch8.12 分词器安装

分词器的主要作用将用户输入的一段文本&#xff0c;按照一定逻辑&#xff0c;分析成多个词语的一种工具 分词器下载地址 analysis-ik Releases infinilabs/analysis-ik GitHub 一个简便 安装方式 安装完成之后 会提示重启&#xff0c;重启es即可 ./bin/elasticsearch-pl…

配置LVS NAT模式

配置LVS NAT模式 环境准备 client1&#xff1a;eth0->192.168.88.10&#xff0c;网关192.168.88.5lvs1: eth0 -> 192.168.88.5&#xff1b;eth1->192.168.99.5web1&#xff1a;eth1->192.168.99.100&#xff1b;网关192.168.99.5web2&#xff1a;eth1->192.168…

基于C语言的“贪吃蛇”游戏设计理念

3.功能描述&#xff1a;本游戏主要实现以下几种功能 图1.游戏功能模块 3.1. 贪吃蛇的控制功能&#xff1a;通过各种条件的判断&#xff0c;实现对游戏蛇的左移、右移、下移、上移、自由移动&#xff0c;贪吃蛇的加长功能。 3.2. 游戏显示更新功能&#xff1a;当贪吃蛇左右移动、…

容器只适用于微服务吗?

容器是一种技术&#xff0c;它将应用及其依赖项打包成一个可移植的单元&#xff0c;以便在不同的计算环境中一致地运行。这种技术确实在微服务架构中得到了广泛应用&#xff0c;因为容器可以帮助实现微服务的快速部署、水平扩展和管理。 然而&#xff0c;容器并不仅限于用于微…

操作系统笔记之进程调用API中的getpid、fork、wait、exec补充

操作系统笔记之进程调用API中的getpid、fork、wait、exec补充 code review! —— 杭州 2024-03-17 夜 文章目录 操作系统笔记之进程调用API中的getpid、fork、wait、exec补充1.getpid()2.fork()3.wait()4.exec()5.通常&#xff0c;exec() 调用与 fork() 调用一起使用&#xff…

Leetcode 3080. Mark Elements on Array by Performing Queries

Leetcode 3080. Mark Elements on Array by Performing Queries 1. 解题思路2. 代码实现 题目链接&#xff1a;3080. Mark Elements on Array by Performing Queries 1. 解题思路 这一题我们只需要按照题意进行一下实现就行了。具体来说的话&#xff0c;我们只需要依序遍历一…

算法笔记p154最大公约数和最小公倍数

目录 最大公约数辗转相除法证明例子代码实现 最小公倍数代码实现 最大公约数 正整数a与b的最大公约数是指a与b的所有公约数中最大的那个公约数&#xff0c;一般用gcd(a, b)表示a和b的最大公约数。 辗转相除法 设a、b均为正整数&#xff0c;则gcd(a, b) gcd(b, a % b)。即被…

【C语言_字符函数和字符串函数_复习篇】

目录 一、字符函数 1.1 字符分类函数 1.2 字符转换函数 二、字符串函数 2.1 strlen函数 2.1.1 strlen函数的使用 2.1.2 strlen函数的模拟实现 2.2 strcpy函数 2.2.1 strcpy函数的使用 2.2.2 strcpy函数的模拟实现 2.3 strcat函数 2.3.1 strcat函数的使用 2.3.2 strcat函数的…