当前位置: 首页 > news >正文

Java Stream 流对象(实用技巧)

目录

一、InputStream & OutputStream

1.1、InputStream 和 OutputStream 一般使用

1.2、特殊使用

1.2.1、如何表示文件读取完毕?(DataInputStream)

1.2.2、字符读取/文本数据读取(Scanner)

1.2.3、文件的随机读写(RandomAccessFile)


一、InputStream & OutputStream


1.1、InputStream 和 OutputStream 一般使用

InputStream 有以下几个方法:

  1. int read():读取一个字节的数据,返回 -1 代表已经完全读完了.
  2. int read(byte[] b):最多读取 b.length 字节的数据到 b 中,返回实际读到的数 量;-1 代表以及读完了(这就像是你去端了个盆,去食堂让阿姨给打饭,那么阿姨肯定是按照她这饭的多少,能给你打满,就尽量给你打满),这也是实际比较常用的方法.
  3. int read(byte[] b, int off, int len):最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返回实际读到的数量;-1 代表以及读完了.
  4. void close():关闭字节流(一般会把 InputStream 写在 try() 中,就不用手动释放了~).

inputStream 只是一个抽象类,要使用还是需要具体的实现类,比如 当客户端和服务器 accept 后,获取流对象具体实现类...... 但是我们最常用的还是文件的读取,也就是 FileInputStream.

OutputStream 有以下几个方法:

  1. void write(int b):将指定的字节写入此输出流.
  2. void write(byte[] b):将 b 这个字符数组中的数据全部写入 os 中.
  3. int write(byte[] b, int off, int len):将 b 这个字符数组中从 off 开始的数据写入 os 中,一共写 len 个
  4. void close():关闭字节流
  5. void flush():我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置, 调用 flush(刷新)操作,将数据刷到设备中。

OutputStream 同样只是一个抽象类,要使用还需要具体的实现类。我们现在还是只关心写入文件中, 所以使用 FileOutputStream

Ps:FileOutputStream 有一个构造器是 new FileOutputStream(String path, boolean append),第一个参数是文件路径,第二个参数是是否以追加到末尾的形式写入,这里如果要在文件末尾追加数据,就需要填写 true 即可~

1.2、特殊使用

1.2.1、如何表示文件读取完毕?(DataInputStream)

使用 read() 方法,返回一个 int 值,这个值如果是 -1,表示文件已经全部读取完毕~

但是实际的项目中,还常常使用一种顺水推舟方式表示文件读取完毕~ 如果我们约定数据的格式,是一个 int (表示 payload 的长度 )+ payload,后面也是一样格式的数据,那么这个时候,我们就需要通过 DataInputStream (这个流对象专门用来读取数字和字节流,必须搭配 DataOutputStream 使用)中的 readInt 方法来读取 这个 int,这个方法特殊就在于读取到文件末尾以后,继续读取就会抛出 EOFException 这个异常(以往我们读取到文件末尾都是返回 -1,或者是 null。),因此这里我们就可以 通过 catch 来捕获这个异常,表示读取完成~

Ps:值得注意的是,DataInputStream / DataOutputStream 可以方便进行数字的读写(readInt、writeInt),原生的 InputStream / OutputStream 没有提供数字读写方法,需要我们自己转化.

    public LinkedList<Message> loadAllMessageFromQueue(MSGQueue queue) throws IOException {//1.检查文件是否存在if(!checkQueueFileExists(queue.getName())) {throw new IOException("[MessageFileManager] 获取文件中所有有效消息时,发现队列文件不存在!queueName=" + queue.getName());}//2.获取队列中所有有效的消息synchronized (queue) {LinkedList<Message> messages = new LinkedList<>();try (InputStream inputStream = new FileInputStream(getQueueDataFilePath(queue.getName()))) {try (DataInputStream dataInputStream = new DataInputStream(inputStream)) {int index = 0;while(true) {int messageSize = dataInputStream.readInt();byte[] payload = new byte[messageSize];int n = dataInputStream.read(payload);if(n != messageSize) {throw new IOException("[MessageFileManager] 读取消息格式出错!expectedSize=" + messageSize +", actualSize=" + n);}//记录 offsetMessage message = (Message) BinaryTool.fromBytes(payload);if(message.getIsValid() == 0x0) {index += (4 + messageSize);continue;}message.setOffsetBeg(index + 4);message.setOffsetEnd(index + 4 + messageSize);messages.add(message);index += (4 + messageSize);}}} catch (EOFException e) {System.out.println("[MessageFileManager] 队列文件中有消息获取完成!queueName=" + queue.getName());}return messages;}}

1.2.2、字符读取/文本数据读取(Scanner)

对字符类型直接使用 InputStream 进行读取是非常麻烦且困难的,所以,我们使用一种我们之前比较熟悉的类来完成该工作,就是 Scanner 类。

Scanner 一般搭配 PrintWrite ,进行文本格式数据的读写,大大省去了 InputStream/OutputStream  还需要将 字节数据 和 文本数据 之间使用 UTF-8 解码转换的操作.

例如一:

// 需要先在项目目录下准备好一个 hello.txt 的文件,里面填充 "你好中国" 的内容public class Main {public static void main(String[] args) throws IOException {try (InputStream is = new FileInputStream("hello.txt")) {try (Scanner scanner = new Scanner(is, "UTF-8")) {while (scanner.hasNext()) {String s = scanner.next();System.out.print(s);}}}}
}

例如二: 

    public void writeStat(String queueName, Stat stat) {try (OutputStream outputStream = new FileOutputStream(getQueueStatFilePath(queueName))) {PrintWriter printWriter = new PrintWriter(outputStream);printWriter.write(stat.totalCount + "\t" + stat.validCount);printWriter.flush();} catch (IOException e) {throw new RuntimeException(e);}}public Stat readStat(String queueName) {Stat stat = new Stat();try (InputStream inputStream = new FileInputStream(getQueueStatFilePath(queueName))) {Scanner scanner = new Scanner(inputStream);stat.totalCount = scanner.nextInt();stat.validCount = scanner.nextInt();return stat;} catch (IOException e) {throw new RuntimeException(e);}}

1.2.3、文件的随机读写(RandomAccessFile)

之前使用 DataInputStream / DataOutputStream 都是接收 FileInputStream/FileOutputStream 进行文件的顺序读写(要么是从头读到尾,要么是在尾部追加写入......),RandomAccessFile 类就特别在可以任意指定位置进行 读/写 操作!

这里涉及到光标的概念,实际上就是你写文件的时候,你写到哪个位置,哪个位置就会有一个光标一闪一闪~

在 RandomAccessFile 中,可以使用 seek() 方法指定光标的位置(单位是字节),例如你要对一个文件中的某一段内存进行逻辑删除(没有实际删除,只是先读出来标记为无效,然后在写回文件,回收站就差不多是这个逻辑).

    public void deleteMessage(MSGQueue queue, Message message) throws IOException {//1.检查队列相关文件是否存在if(!checkQueueFileExists(queue.getName())) {throw new IOException("[FileDataCenter] 删除消息时,发现队列相关文件不存在!queueName=" + queue.getName());}synchronized (message) {//2.将要删除的消息文件读出来try (RandomAccessFile randomAccessFile = new RandomAccessFile(getQueueDataFilePath(queue.getName()), "rw")) {randomAccessFile.seek(message.getOffsetBeg() - 4);int payloadSize = randomAccessFile.readInt();byte[] payload = new byte[payloadSize];int n = randomAccessFile.read(payload);if(n != payloadSize) {throw new IOException("[FileDataCenter] 读取文件格式出错!path=" + getQueueDataFilePath(queue.getName()));}//3.将待删除的消息标记为无效(isValid = 0x0)Message toDeleteMessage = (Message) BinaryTool.fromBytes(payload);toDeleteMessage.setIsValid((byte) 0x0);//4.将消息写入文件randomAccessFile.seek(message.getOffsetBeg());randomAccessFile.write(BinaryTool.toBytes(toDeleteMessage));}//5.更新统计文件Stat stat = readStat(queue.getName());stat.validCount -= 1;writeStat(queue.getName(), stat);}}

Ps:

RandomAccessFile 的有两种构造器(实际上是一种),RandomAccessFile(String name, String mode)等价于RandomAccessFile(new File(name), String mode)

mode 这个参数表示 访问模式~
➢ "r":以只读方式打开指定文件。如果试图对该RandomAccessFile执行写入方法,都将抛出IOException异常。
➢ "rw":以读、写方式打开指定文件。如果该文件尚不存在,则尝试创建该文件。
➢ "rws":以读、写方式打开指定文件。相对于"rw"模式,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
➢ "rwd":以读、写方式打开指定文件。相对于"rw"模式,还要求对文件内容的每个更新都同步写入到底层存储设备。

相关文章:

Java Stream 流对象(实用技巧)

目录 一、InputStream & OutputStream 1.1、InputStream 和 OutputStream 一般使用 1.2、特殊使用 1.2.1、如何表示文件读取完毕&#xff1f;&#xff08;DataInputStream&#xff09; 1.2.2、字符读取/文本数据读取&#xff08;Scanner&#xff09; 1.2.3、文件的随机…...

【用unity实现100个游戏之8】用Unity制作一个炸弹人游戏

文章目录 前言素材开始一、绘制地图二、玩家设置三、玩家移动四、玩家四方向动画运动切换 五、放置炸弹六、生成爆炸效果七、墙壁和可破坏障碍物的判断八、道具生成和效果九、玩家死亡十、简单的敌人AI十一、简单敌人AI十二、随机绘制地图十三、虚拟摇杆 最终效果待续源码完结 …...

简易版人脸识别qt opencv

1、配置文件.pro #------------------------------------------------- # # Project created by QtCreator 2023-09-05T19:00:36 # #-------------------------------------------------QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsTARGET 01_face TEMP…...

如何系统地学习 JavaScript?

前言 在学习JavaScript前需要先将Html和Css的相关知识点弄清楚&#xff0c;Js的很多操作是要结合Html和Css&#xff0c;下面我总结了Html、Css和Js的相关学习知识点供参考&#xff0c;希望对你有所帮助喔~ Html 文档学习 【HTML 】w3school教程 :https://www.w3school.com.…...

对称二叉树(Leetcode 101)

题目 101. 对称二叉树 思路 使用层序遍历&#xff0c;遍历当前层的节点时&#xff0c;如该节点的左&#xff08;右&#xff09;孩子为空&#xff0c;在list中添加null&#xff0c;否则加入左&#xff08;右&#xff09;孩子的值。每遍历完一层则对当前list进行判断&#xff0c…...

动手学深度学习(2)-3.5 图像分类数据集

文章目录 引言正文图像分类数据集主要包介绍主要流程具体代码练习 总结 引言 这里主要是看一下如何加载数据集&#xff0c;并且生成批次训练的数据。最大的收获是&#xff0c;知道了如何在训练阶段提高模型训练的性能 增加batch_size增加num_worker数据预加载 正文 图像分类…...

C标准输入与标准输出——stdin,stdout

&#x1f517; 《C语言趣味教程》&#x1f448; 猛戳订阅&#xff01;&#xff01;&#xff01; ​—— 热门专栏《维生素C语言》的重制版 —— &#x1f4ad; 写在前面&#xff1a;这是一套 C 语言趣味教学专栏&#xff0c;目前正在火热连载中&#xff0c;欢迎猛戳订阅&#…...

如何将home目录空间扩充到根目录下

目录 1、查看查看磁盘使用情况2、扩容思路3、卸载并删除/home4、扩大/root逻辑卷5、扩大/文件系统6、重建/home逻辑卷7、创建/home文件系统8、将新建的文件系统挂载到/home目录下9、恢复/home并删除备份10、再次查看看磁盘存储 系统&#xff1a;centos7.9 1、查看查看磁盘使用…...

Ceph PG Peering数据修复

ceph数据修复 当PG完成了Peering过程后&#xff0c;处于Active状态的PG就可以对外提供服务了。如果该PG的各个副本上有不一致的对象&#xff0c;就需要进行修复。 Ceph的修复过程有两种&#xff1a;Recovery和Backfill。 Recovery是仅依据PG日志中的缺失记录来修复不一致的对…...

服务器上使用screen和linux的基本操作

临时换源 pip install torch1.7.1 -i https://pypi.tuna.tsinghua.edu.cn/simple some-package pip install torch1.7.1 -i http://pypi.douban.com/simple some-package临时清华源和豆瓣源 配环境的一点小问题 我们尽量是去配置能满足代码的环境&#xff0c;而不要想着修改…...

Kafka3.0.0版本——文件存储机制

这里写木目录标题 一、Topic 数据的存储机制1.1、Topic 数据的存储机制的概述1.2、Topic 数据的存储机制的图解1.3、Topic 数据的存储机制的文件解释 二、Topic数据的存储位置示例 一、Topic 数据的存储机制 1.1、Topic 数据的存储机制的概述 Topic是逻辑上的概念&#xff0c…...

Linux如何安装MySQL

Linux安装MySQL5.7 1、下载 官网下载地址&#xff1a;http://dev.mysql.com/downloads/mysql/ 2、复制下面几个文件 3、检查当前系统是否安装过mysql、检查当前mysql依赖环境、检查/tmp文件夹权限 1&#xff09;检查当前系统是否安装过mysql&#xff0c;执行安装命令前&am…...

确保网络的安全技术介绍

防火墙技术 防火墙是隔离本地网络与外界网络的一道防御系统。通常用于内部局域网 与外部广域网之间&#xff0c;通过限制外部网络用户以非法手段来访问内部资源&#xff0c;来达到保 护内部网络的安全。根据安全规则&#xff0c;防火墙对任何外部网络访问内部网络的行为进 …...

机器学习练习

原文章添加链接描述...

算法通关村第十九关——最小路径和

LeetCode64. 给定一个包含非负整数的 m n 网格 grid,请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 输入&#xff1a;grid[[1,3,1],[1,5,1],[4,2,1]] 输出&#xff1a;7 解释&#xff1a;因为路径1→3→1→1→1的总和最小。 public int minPath…...

Linux 访问进程地址空间函数 access_process_vm

文章目录 一、源码解析二、Linux内核 用途2.1 ptrace请求2.2 进程的命令行 参考资料 一、源码解析 /*** get_task_mm - acquire a reference to the tasks mm** Returns %NULL if the task has no mm. Checks PF_KTHREAD (meaning* this kernel workthread has transiently a…...

selenium 动态爬取页面使用教程以及使用案例

Selenium 介绍 概述 Selenium是一款功能强大的自动化Web浏览器交互工具。它可以模拟真实用户在网页上的操作&#xff0c;例如点击、滚动、输入等等。Selenium可以爬取其他库难以爬取的网站&#xff0c;特别是那些需要登录或使用JavaScript的网站。Selenium可以自动地从Web页面…...

小程序中如何查看会员的积分和变更记录

​积分是会员卡的一个重要功能&#xff0c;可以用于激励会员消费和提升用户粘性。在小程序中&#xff0c;商家可以方便地查看会员卡的积分和变更记录&#xff0c;以便更好地了解会员的消费行为和积分变动情况。下面将介绍如何在小程序中查看会员卡的积分和变更记录。 1. 找到指…...

音视频 ffmpeg命令直播拉流推流

直播拉流 ffplay rtmp://server/live/streamName ffmpeg -i rtmp://server/live/streamName -c copy dump.flv对于不是rtmp的协议 -c copy要谨慎使用 直播推流 ffmpeg -re -i out.mp4 -c copy flvrtmp://server/live/streamName参数&#xff1a;-re,表示按时间戳读取文件 参…...

Python钢筋混凝土结构计算.pdf-T001-混凝土强度设计值

以下是使用Python求解上述问题的完整代码&#xff1a; # 输入参数 f_ck 35 # 混凝土的特征抗压强度&#xff08;单位&#xff1a;MPa&#xff09; f_cd 25 # 混凝土的强度设计值&#xff08;单位&#xff1a;MPa&#xff09; # 求解安全系数 gamma_c f_ck / f_cd # …...

长风破浪会有时,直挂云帆济沧海!(工作室年会总结)

前言 我也是有段时间没写过总结性的博客了。最近是很忙的&#xff0c;尤其是年会那两天&#xff0c;我甚至可以说这是我这辈子目前最忙的两天。但这段经历还是很值得我记录下来的&#xff0c;也是给后面有需要的人提供的一些建议。我个人也是第一次筹办这种大型些的活动&#x…...

(数字图像处理MATLAB+Python)第十一章图像描述与分析-第五、六节:边界描述和矩描述

文章目录 一&#xff1a;边界描述&#xff08;1&#xff09;边界链码A&#xff1a;概述B&#xff1a;边界链码改进C&#xff1a;程序 &#xff08;2&#xff09;傅里叶描绘子A&#xff1a;概述B&#xff1a;程序 二&#xff1a;矩描述&#xff08;1&#xff09;矩A&#xff1a;…...

Redis之bigkey问题解读

目录 什么是bigkey&#xff1f; bigkey引发的问题 如何查找bigkey redis-cli --bigkeys MEMORY USAGE bigKey如何删除 渐进式删除 unlink bigKey生产调优 什么是bigkey&#xff1f; bigkey简单来说就是存储本身的key值空间太大&#xff0c;或者hash&#xff0c;list&…...

ElementUI浅尝辄止27:Steps 步骤条

引导用户按照流程完成任务的分步导航条&#xff0c;可根据实际应用场景设定步骤&#xff0c;步骤不得少于 2 步。 1.如何使用&#xff1f; 设置active属性&#xff0c;接受一个Number&#xff0c;表明步骤的 index&#xff0c;从 0 开始。需要定宽的步骤条时&#xff0c;设置s…...

React 18 迁移状态逻辑至 Reducer 中

参考文章 迁移状态逻辑至 Reducer 中 对于拥有许多状态更新逻辑的组件来说&#xff0c;过于分散的事件处理程序可能会令人不知所措。对于这种情况&#xff0c;可以将组件的所有状态更新逻辑整合到一个外部函数中&#xff0c;这个函数叫作 reducer。 使用 reducer 整合状态逻…...

【SA8295P 源码分析】89 - QNX AIS Camera qcarcam_test 可执行程序 main() 函数 源代码流程分析

【SA8295P 源码分析】89 - QNX AIS Camera qcarcam_test 可执行程序 main 函数 源代码流程分析 一、qcarcam_test.cpp main() 函数源码分析二、qcarcam_test_setup_input_ctxt_thread( ) :初始化 gCtxt.inputs[input_idx] 上下文环境三、process_cb_event_thread( ) :负责处理…...

STM32屏幕计时器

目录 一、最终效果二、实现思想三、实现过程3.1 屏幕显示3.2 中断处理 一、最终效果 显示屏显示计时时间&#xff0c;格式为 00:00:00&#xff0c;依次为 时:分:秒&#xff0c;程序运行之后自动计时&#xff0c;当按下按键&#xff0c;计时清零&#xff0c;按下按键采用外部中…...

MRI多任务技术及应用

目录 一、定量心血管磁共振成像&#xff08;CMR&#xff09;的改进方法二、磁共振多任务三、磁共振多任务的成像框架四、磁共振多任务的图像模型和采样和重建策略五、利用MR多任务进行快速三维稳态CEST(ss-CEST)成像5.1 利用MR多任务进行快速三维稳态CEST(ss-CEST)成像介绍5.2 …...

app自动化测试(Android)

Capability 是一组键值对的集合&#xff08;比如&#xff1a;"platformName": "Android"&#xff09;。Capability 主要用于通知 Appium 服务端建立 Session 需要的信息。客户端使用特定语言生成 Capabilities&#xff0c;最终会以 JSON 对象的形式发送给 …...

【力扣每日一题】2023.9.3 消灭怪物的最大数量

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目比较长&#xff0c;我概括一下就是有一群怪物&#xff0c;每只怪物离城市的距离都不一样&#xff0c;并且靠近的速度也不一样&#x…...