【节点流和处理流】

article/2025/9/14 12:22:15

节点流和处理流

基本介绍

  1. 节点流可以从特定数据源读取数据,如FileReader、FileWriter
  2. 处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader.处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。
  • 节点流和处理流一览

image-20220130123744014

以BuffredReader为例,它里面有个Reader属性,说明它可以处理一个节点流,只要是Reader的子类就可以。

image-20220130124026684 image-20220130124729773

同样,BufferedWriter里也封装了一个Writer,说明它可以处理一个节点流,只要是Writrer的子类就可以。

image-20220130124920068 image-20220130125107660

这种设计模式叫做修饰器模式

节点流和处理流的区别和联系

  1. 节点流是底层流/低级流,直接跟数据源连接。
  2. 处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入和输出。
  3. 处理流对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连接。

处理流的功能体现

  1. 性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
  2. 操作的便捷:处理流可能提供了一系列便捷的方法来一次性输入和输出大批量的数据,使用更加灵活方便。

处理流-BufferedReader和BufferedWriter

  • BufferedReader和BufferedWriter属于字节流,是按照字符来读取数据的。
  • 关闭处理流时,只要关闭外层流即可

应用案例1 使用BufferedReader读取文本文件,并显示在控制台

String fileName = "D:\\Test\\test.txt";
//创建BufferedReader
BufferedReader bufferedReader = new BufferedReader(new FileReader(fileName));
//读取
String line;
//readLine()按行读取文件,如果已到达流末尾,则返回 null
while ((line = bufferedReader.readLine()) != null) {System.out.println(line);
}
//关闭流,底层会自动关闭节点流
bufferedReader.close();

应用案例2 使用BufferedWriter将"Hello,world"写入文件

String fileName = "D:\\Test\\hw.txt";
String content = "Hello,world";
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(fileName));
bufferedWriter.write(content);
bufferedWriter.newLine();//插入一个和系统相关的换行符
bufferedWriter.write(content);
bufferedWriter.close();
System.out.println("写入成功");

image-20220130143217039

应用案例3 使用ufferedReader和BufferedWriter完成文本文件的拷贝

String originName = "D:\\Test\\test.txt";
String targetName = "D:\\Test\\test_copy.txt";
//创建bufferedReader
BufferedReader bufferedReader = new BufferedReader(new FileReader(originName));
//创建bufferedWriter
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(targetName));
//按行读取文件
String line;
while((line = bufferedReader.readLine())!= null){//按行写入bufferedWriter.write(line);//换行bufferedWriter.newLine();
}
bufferedReader.close();
bufferedWriter.close();
System.out.println("拷贝完毕");

处理流-BufferedInputStream和BufferedOutputStream

介绍BufferedInputStream

BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 markreset 方法的能力。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark 操作记录输入流中的某个点,reset 操作使得在从包含的输入流中获取新字节之前,再次读取自最后一次 mark 操作后读取的所有字节。

image-20220130144216005

介绍BufferedOutputStream

BufferedOutputStream类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。

image-20220130144621381

应用案例 使用BufferedInputStream和BufferedOutputStream完成图片/音乐的拷贝

String originName = "D:\\Test\\testpicture.png";
String targetName = "D:\\Test\\Test2\\testpicture.png";
//创建BufferedInputStream
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(originName));
//创建BufferedOutputStream
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(targetName));
byte[] bytes = new byte[1024];
int readLen;
while ((readLen = bufferedInputStream.read(bytes))!=-1){bufferedOutputStream.write(bytes,0,readLen);
}
//关闭流
bufferedInputStream.close();
bufferedOutputStream.close();System.out.println("拷贝完毕");

对象流-ObjectInputStream和ObjectOutputStream

为什么需要对象流?

比如,当我们将int num = 100这个数据直接保存到文件中,注意不是 100 数字,而是int 100,并且我们需要能够直接从文件中恢复int 100;又比如将Dog dog = new Dog(“小黄”,3)这个dog对象保存到文件中,并且能够从文件中恢复。

以上要求,就是能够将 基本数据类型 或者 对象 进行 序列化 和 反序列化操作

序列化和反序列化

  1. 序列化就是在保存数据时,保存数据的数据类型
  2. 反序列化就是在恢复数据时,恢复数据的数据类型
  3. 为了让对象支持序列化机制,必须让它的类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:
    • Serializable :一般推荐这个
    • Externalizable :继承了Serializable,需要实现方法

image-20220131110334975

ObjectInputStream

ObjectInputStream的一个构造方法需要传入InputStream,说明了其实它的设计也是修饰器模式。

image-20220131110924628

ObjectOutputStream

image-20220131111213963

应用案例1 使用ObjectOutputStream序列化基本数据类型和一个Dog对象(name, age),并保存到data.dat文件中

//必须实现可序列化
public class Dog implements Serializable {private String name;private int age;public Dog(String name, int age) {this.name = name;this.age = age;}
}
public class ObjectOutputStream_ {public static void main(String[] args) throws IOException {//序列化后保存的文件格式不是纯文本,而是按照他的格式String fileName = "D:\\Test\\data.dat";ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName));//序列化数据到该文件中oos.write(100);//int 自动装箱成Integer,而Integer在底层是实现了Serializable的oos.writeBoolean(true);//底层是实现了Serializable的oos.writeChar('a');//底层是实现了Serializable的oos.writeDouble(9.5);//底层是实现了Serializable的oos.writeUTF("清华大学");//String//保存一个Dog对象oos.writeObject(new Dog("旺财", 10));oos.close();System.out.println("数据保存完毕(序列化形式)");}
}

应用案例2 使用ObjectInputStream读取data.dat并反序列化恢复数据

public class ObjectInputStream_ {public static void main(String[] args) throws IOException, ClassNotFoundException {//指定反序列化文件String fileName = "D:\\Test\\data.dat";ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName));//读取(反序列化)//1. 读取的顺序需要和保存数据的顺序一致,否则会出现异常System.out.println(ois.readInt());System.out.println(ois.readBoolean());System.out.println(ois.readChar());System.out.println(ois.readDouble());System.out.println(ois.readUTF());//dog的编译类型是 Object,运行类型是DogObject dog = ois.readObject();System.out.println("运行类型 = " + dog.getClass());System.out.println("dog = " + dog);//底层Object->Dog//如果我们要使用Dog的方法,需要向下转型Dog myDog = (Dog)dog;System.out.println(myDog.getAge());//关闭流,关闭外层流即可ois.close();System.out.println("读取完毕");}
}

注意事项和相关细节

  1. 读写顺序要一致
  2. 要求实现序列化或反序列化对象,需要实现Serializable
  3. 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
    private static final long serialVersionUID = 1L;
  4. 序列化对象时,默认将里面所有属性都进行序列化,但除了statictransient修饰的成员
  5. 序列化对象时,要求里面属性的类型也需要实现序列化接口
  6. 序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化

标准输入和输出流

  • System.in 标准输入
  • System.out 标准输出
//public static final InputStream in = null;
//System.in的编译类型是 InputStream
//System.in的运行类型是 BufferedInputStream
//表示的是标准输入:键盘
System.out.println(System.in.getClass());//public static final PrintStream out = null;
//System.out的编译类型是 PrintStream
//System.out的运行类型是 PrintStream
//表示的是标准输出:屏幕
System.out.println(System.out.getClass());System.out.println("尝试System.out.println()");
Scanner scanner = new Scanner(System.in);
System.out.println("请输入内容:");
String next = scanner.next();
System.out.println("next = " + next);

转换流-InputStreamReader和OutputStreamWriter

image-20220131131116175

image-20220131131631194
String fileName = "D:\\Test\\b.txt";//1. 创建输入流
BufferedReader br = new BufferedReader(new FileReader(fileName));
//2. 读取,默认情况下按照UTF-8
String s = br.readLine();
System.out.println("读取的内容: " + s);
br.close();

默认情况下文本文件存储按照UTF-8。


现在另存b.txt为ANSI国标码(每个国家不一样,在我的系统中为GBK)

此时在运行发现乱码了

image-20220131131926214

因为我们没有指定读取文件的编码方式!

有转换流就可以乱码问题。

InputStreamReader类图

image-20220131132323649

能够发现有一个构造器image-20220131132454582

能够传入一个InputStream对象,同时可以指定编码方式!!!

OutputStreamWriter类图

image-20220131132336785

应用案例1 演示InputStreamReader

演示使用 InputStreamReader 转换流解决中文乱码问题,将字节流 FileInputStream 转成字符流 InputStreamReader

指定编码 gbk或者utf-8

String fileName = "D:\\Test\\b2.txt";FileInputStream fileInputStream = new FileInputStream(fileName);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "gbk");
char[] chars = new char[8];
int readLen;
while ((readLen = inputStreamReader.read(chars)) != -1){System.out.println(new String(chars, 0, readLen));
}
inputStreamReader.close();
System.out.println("-------------------------------------");
System.out.println("读取完毕");

此时正常输出

image-20220131133555237

应用案例1 演示OutputStreamWriter

String content = "我要上清华!";
String fileName = "D:\\Test\\b3.txt";
FileOutputStream fileOutputStream = new FileOutputStream(fileName);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "gbk");
outputStreamWriter.write(content);
outputStreamWriter.close();
System.out.println("-------------------------------------");
System.out.println("以gbk编码写入完毕");

打印流-PrintStream和PrintWriter

打印流只有输出流,没有输入流

PrintStream类图

在这里插入图片描述

PrintWriter类图

image-20220201115506368

应用案例1 演示PrintStream

PrintStream out = System.out;
// PrintStream输出数据的位置是 标准输出,即显示器
out.print("我爱学JAVA,");
out.write("我要上清华".getBytes());out.close();

我们还可以修改打印输出的位置/设备

//我们可以修改打印流的输出位置/设备
System.setOut(new PrintStream("D:\\Test\\f1.txt"));
System.out.println("我要上清华!");

应用案例2 演示PrintWriter

打印到显示器

PrintWriter printWriter = new PrintWriter(System.out);
printWriter.print("我爱Java!");
printWriter.close();

打印到文件

PrintWriter printWriter = new PrintWriter(new FileWriter("E:\\Test\\t2.txt"));
printWriter.print("我爱Java!");
printWriter.close();

http://chatgpt.dhexx.cn/article/mKmwvLdp.shtml

相关文章

流数据处理

流数据处理strom 在2011年Storm开源之前,由于Hadoop的火红,整个业界都在喋喋不休地谈论大数据。Hadoop的高吞吐,海量数据处理的能力使得人们可以方便地处理海量数据。但是,Hadoop的缺点也和它的优点同样鲜明——延迟大&#xff0…

一. 流式处理简介

https://www.cnblogs.com/shenlanzhizun/p/6027042.html Java技术学习 https://www.itkc8.com 一. 流式处理简介 在我接触到java8流式处理的时候,我的第一感觉是流式处理让集合操作变得简洁了许多,通常我们需要多行代码才能完成的操作,借助…

Kafka基础-流处理

1. 什么是流处理? 首先,让我们说一下什么是数据流(也称为事件流)?它是无边界数据集的抽象说法,无边界意味着无限且不断增长,因为随着时间的推移,新数据会不断地到来。 除了无边界的…

流处理基本介绍

1. 什么是流处理 一种被设计来处理无穷数据集的数据处理系统引擎 2. 流处理的几个概念 1. 无穷数据(Unbounded data):一种持续生成,本质上是无穷尽的数据集。它经常会被称为“流数据”。然而,用流和批次来定义…

Spark Streaming与流处理

一、流处理 1.1 静态数据处理 在流处理之前,数据通常存储在数据库,文件系统或其他形式的存储系统中。应用程序根据需要查询数据或计算数据。这就是传统的静态数据处理架构。Hadoop 采用 HDFS 进行数据存储,采用 MapReduce 进行数据查询或分…

什么是流处理

流处理正变得像数据处理一样流行。流处理已经超出了其原来的实时数据处理的范畴,它正在成为一种提供数据处理(包括批处理),实时应用乃至分布式事务的新方法的技术。 1、什么是流处理? 流处理是不断合并新数据以计算结果…

嵌入式软件升级方法

一、U盘升级 1.在u盘根目录新建文件夹,命名为‘upgrade’ 2.将软件复制到upgrade文件夹中 3.将u盘插到嵌入式服务器usb口上,断电重启服务器 二、PC工具升级 1.打开PC工具,选中要升级的机器,点击‘素材管理’选项卡&#xff0c…

嵌入式软件架构设计之分层设计

关注、星标公众号,不错过精彩内容 整理:黄工 素材来源:网络 参考来源: https://blog.51cto.com/kenotu/1614390 在正规的项目开发中,项目往往是并行开发的,也就是说硬件设计、底层软件设计、应用软件设计等…

嵌入式系统软件层次结构

文章目录 嵌入式系统软件嵌入式系统软件的层次结构硬件抽象层 嵌入式操作系统嵌入式操作系统——WinCE嵌入式操作系统——VxWorks嵌入式操作系统——Linux嵌入式Linux OS的特点 嵌入式操作系统——uCOS嵌入式操作系统—— PalmOS其他嵌入式操作系统华为鸿蒙系统 嵌入式系统软件…

嵌入式软件开发必备知识体系

嵌入式软件开发学习路线 前言 本章节主要介绍嵌入式软件开发概念以及大致的学习知识点的范围 一、嵌入式软件是什么? 百度百科:嵌入式工程师是指具有C/C语言、汇编语言等基础,熟悉模拟电子技术等硬件知识,了解处理器体系结构&a…

嵌入式开发 | 嵌入式开发设计文档该怎么写?

关注星标公众号,不错过精彩内容 作者 | strongerHuang 微信公众号 | 嵌入式专栏 俗话说,不会写文档的工程师不是好的工程师! 如果你只会写代码,而从不写文档,迟早有一天会“出事”。这不是危言耸听,现实生活…

简单嵌入式系统软件架构

本文为原创,以下链接有比较及时的更新: https://www.yuque.com/docs/share/334f4a3d-2974-49db-8f68-4db6601a0d21?# 《简单嵌入式系统》 引言 本文描述的内容,适用范围是简单嵌入式系统。举一些可能不恰当的例子,如手环、蓝牙…

嵌入式软件设计层级划分概念

嵌入式软件设计层级划分概念 设计过程中体会的细化更新部分: 层级描述备注应用层直接控制应用,比如led_light_on(),led_light_off() 器件层(如果操作复杂可进一步划分为器件应用层和器件驱动层)比如:实现led_light_on …

浅议嵌入式软件测试

近年来,随着嵌入式系统的功能和复杂性不断增加,其开发时间和成本也随之不断上升。对于安全关键领域的嵌入式系统和软件来说,其稳定性和可靠性往往需要通过大量的测试和验证来保证。 01.一般软件测试vs嵌入式软件测试 嵌入式软件测试针对嵌入…

嵌入式程序设计思路

项目做的多了,深切地体会到架构的重要性。 俗话说,没有好的架构,移植和复用是件很痛苦的事,只能重复的造轮子。特别是嵌入式的代码,如果应用层中间穿插着驱动层的代码,维护起来是一件相当痛苦的事情。 这…

嵌入式应用软件架构设计

要做到嵌入式应用的代码逻辑清晰,且避免重复的造轮子,没有好的应用架构怎么行。 如果没有好的架构,移植将会是一件很痛苦的事情。 如果没有好的架构,复用是最大的难题,没法更大限度的复用原有的代码。 如果没有好的架…

嵌入式软件设计(1)--概述

嵌入式软件的定义及特点 嵌入式系统的定义 嵌入式系统是以应用为中心,以计算机技术为基础,软硬件可裁剪、功能、可靠性、功耗严格要求的专用计算机系统。 其中要说明的几个点是 1. 嵌入式系统是专用系统,而不是通用系统,其往往…

嵌入式软件设计必看书籍

提高C语言编程能力 以上4本书籍可以提高C语言编程能力,深入理解C语言指针用法,深入理解C语言标准。 提高软件架构设计能力 以上2本书籍掌握以下知识: 1、软件设计原则。 2、软件设计模式。 3、软件设计构架。 4、软件设计思维。 提升对RTO…

嵌入式软件架构的设计

嵌入式软件架构的设计 大多数嵌入式程序员学习编程,都是从开发板的附带例程开始。之后工作也会继续参考那些例程,很多编程习惯、方式也会受之影响。 其实开发板式的编程方式与工作中实际需求的并不完全一致。 开发板的通常卖给初学者,注重…

嵌入式软件设计(stm32快速上手)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 有很多的培训机构在培训嵌入式的时候,一上来会讲很多的理论知识。其实这个时候要是能通过实操帮助学员快速入门、快速上手、快速看到效果,或许这才是最重要的。 1、安装mdk软件 类…