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

java IO流(二) 字符流 缓冲流 原始流与缓冲流性能分析

请添加图片描述

字符流

前面学习的字节流虽然可以读取文件中的字节数据,但是如果文件中有中文,使用字节流来读取,就有可能读到半个汉字的情况,这样会导致乱码。虽然使用读取全部字节的方法不会出现乱码,但是如果文件过大又不太合适。
所以Java专门提供了另外一种流,叫字符流,字符流是专门为读取文本数据而生的。

FileReader类 读取字符
FileReader读取文件的步骤如下:

第一步:创建FileReader对象与要读取的源文件接通
第二步:调用read()方法读取文件中的字符
第三步:调用close()方法关闭流

请添加图片描述

public class FileReaderTest1 {public static void main(String[] args)  {try (// 1、创建一个文件字符输入流管道与源文件接通Reader fr = new FileReader("io-app2\\src\\01.txt");){// 2、一个字符一个字符的读(性能较差)
//            int c; // 记住每次读取的字符编号。
//            while ((c = fr.read()) != -1){
//                System.out.print((char) c);
//            }// 每次读取一个字符的形式,性能肯定是比较差的。// 3、每次读取多个字符。(性能是比较不错的!)char[] buffer = new char[3];int len; // 记住每次读取了多少个字符。while ((len = fr.read(buffer)) != -1){// 读取多少倒出多少System.out.print(new String(buffer, 0, len));}} catch (Exception e) {e.printStackTrace();}}
}

FileWriter类 写字符
FileWriter往文件中写字符数据的步骤如下:

第一步:创建FileWirter对象与要读取的目标文件接通
第二步:调用write(字符数据/字符数组/字符串)方法读取文件中的字符
第三步:调用close()方法关闭流

请添加图片描述

public class FileWriterTest2 {public static void main(String[] args) {try (// 0、创建一个文件字符输出流管道与目标文件接通。// 覆盖管道// Writer fw = new FileWriter("io-app2/src/02out.txt");// 追加数据的管道Writer fw = new FileWriter("io-app2/src/02out.txt", true);){// 1、public void write(int c):写一个字符出去fw.write('a');fw.write(97);//写了个a//fw.write('磊'); // 写一个字符出去fw.write("\r\n"); // 换行符 win平台是\n 但是\r\n能兼容更多平台// 2、public void write(String c)写一个字符串出去fw.write("我爱你中国abc");fw.write("\r\n");// 3、public void write(String c ,int pos ,int len):写字符串的一部分出去fw.write("我爱你中国abc", 0, 5);fw.write("\r\n");// 4、public void write(char[] buffer):写一个字符数组出去char[] buffer = {'黑', '马', 'a', 'b', 'c'};fw.write(buffer);fw.write("\r\n");// 5、public void write(char[] buffer ,int pos ,int len):写字符数组的一部分出去fw.write(buffer, 0, 2);fw.write("\r\n");} catch (Exception e) {e.printStackTrace();}}
}

这里有一个小问题,FileWriter写完数据之后,必须刷新或者关闭,写出去的数据才能生效。
比如:下面的代码只调用了写数据的方法,没有关流的方法。当你打开目标文件时,是看不到任何数据的。

//1.创建FileWriter对象
Writer fw = new FileWriter("io-app2/src/03out.txt");//2.写字符数据出去
fw.write('a');
fw.write('b');
fw.write('c');

而下面的代码,加上了flush()方法之后,数据就会立即到目标文件中去。

//1.创建FileWriter对象
Writer fw = new FileWriter("io-app2/src/03out.txt");//2.写字符数据出去
fw.write('a');
fw.write('b');
fw.write('c');//3.刷新
fw.flush(); 

下面的代码,调用了close()方法,数据也会立即到文件中去。因为close()方法在关闭流之前,会将内存中缓存的数据先刷新到文件,再关流。

//1.创建FileWriter对象
Writer fw = new FileWriter("io-app2/src/03out.txt");//2.写字符数据出去
fw.write('a');
fw.write('b');
fw.write('c');//3.关闭流
fw.close(); //会先刷新,再关流

但是需要注意的是,关闭流之后,就不能在对流进行操作了。否则会出异常


缓冲流

请添加图片描述

缓冲流有四种,如上图所示.缓冲流的作用:可以对原始流进行包装,提高原始流读写数据的性能。

字节缓冲流
其是在缓冲流的底层自己封装了一个长度为8KB(8129byte)的字节数组,但是缓冲流不能单独使用,它需要依赖于原始流。
读数据时它先用原始字节输入流一次性读取8KB的数据存入缓冲流内部的数组中,再从8KB的字节数组中读取一个字节或者多个字节。
写数据时 它是先把数据写到缓冲流内部的8BK的数组中,等数组存满了,再通过原始的字节输出流,一次性写到目标文件中去。

请添加图片描述

请添加图片描述

在创建缓冲字节流对象时,需要封装一个原始流对象进来。构造方法如下

请添加图片描述

PS构造函数第二个参数可以指定底层封装的字节数组大小,默认为8k。

如果我们用缓冲流复制文件,代码写法如下:

public class BufferedInputStreamTest1 {public static void main(String[] args) {try (InputStream is = new FileInputStream("io-app2/src/01.txt");// 1、定义一个字节缓冲输入流包装原始的字节输入流InputStream bis = new BufferedInputStream(is);OutputStream os = new FileOutputStream("io-app2/src/01_bak.txt");// 2、定义一个字节缓冲输出流包装原始的字节输出流OutputStream bos = new BufferedOutputStream(os);){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();}}
}

字符缓冲流
它的原理和字节缓冲流是类似的,它底层也会有一个8KB的数组,但是这里是字符数组。字符缓冲流也不能单独使用,它需要依赖于原始字符流一起使用。构造方法如下

请添加图片描述

请添加图片描述

BufferedReader还有新增的方法,一次可以读取文本文件中的一行:

请添加图片描述

BufferedWriter还有新增的方法,可以用来写一个换行符:

请添加图片描述

使用BufferedReader读取数据的代码如下

public class BufferedReaderTest2 {public static void main(String[] args)  {try (Reader fr = new FileReader("io-app2\\src\\04.txt");// 创建一个字符缓冲输入流包装原始的字符输入流BufferedReader br = new BufferedReader(fr);){
//            char[] buffer = new char[3];
//            int len;
//            while ((len = br.read(buffer)) != -1){
//                System.out.print(new String(buffer, 0, len));
//            }
//            System.out.println(br.readLine());
//            System.out.println(br.readLine());
//            System.out.println(br.readLine());
//            System.out.println(br.readLine());String line; // 记住每次读取的一行数据while ((line = br.readLine()) != null){System.out.println(line);}} catch (Exception e) {e.printStackTrace();}}
}

使用BufferedWriter往文件中写入字符数据

public class BufferedWriterTest3 {public static void main(String[] args) {try (Writer fw = new FileWriter("io-app2/src/05out.txt", true);// 创建一个字符缓冲输出流管道包装原始的字符输出流BufferedWriter bw = new BufferedWriter(fw);){bw.write('a');bw.write(97);bw.write('磊');bw.newLine();bw.write("我爱你中国abc");bw.newLine();} catch (Exception e) {e.printStackTrace();}}
}

缓冲流性能分析
我们说缓冲流内部多了一个数组,可以提高原始流的读写性能。它和我们使用原始流,自己加一个8BK数组不是一样的吗? 缓冲流就一定能提高性能吗?结论:缓冲流不一定能提高性能。缓冲流的性能不一定比低级流高,其实低级流自己加一个数组,性能其实是不差,只不过缓冲流帮你加了一个相对而言大小比较合理的数组 。

下面我们用一个比较大的文件(889MB)进行复制,做性能测试,分别使用下面四种方式来完成文件复制,并记录文件复制的时间。


1使用低级流一个字节一个字节的复制2使用低级流按照字节数组的形式复制3使用缓冲流一个字节一个字节的复制4使用缓冲流按照字节数组的形式复制低级流一个字节复制: 慢得简直让人无法忍受
低级流按照字节数组复制(数组长度1024): 12.117s
缓冲流一个字节复制: 11.058s
缓冲流按照字节数组复制(数组长度1024): 2.163s

经过上面的测试,我们可以得出一个结论:默认情况下,采用一次复制1024个字节,缓冲流完胜。
但是,缓冲流就一定性能高吗?我们采用一次复制8192个字节试试

低级流按照字节数组复制(数组长度8192): 2.535s
缓冲流按照字节数组复制(数组长度8192): 2.088s

经过上面的测试,我们可以得出一个结论:一次读取8192个字节时,低级流和缓冲流性能相当。相差的那几毫秒可以忽略不计。
继续把数组变大,看一看缓冲流就一定性能高吗?现在采用一次读取1024*32个字节数据试试(缓冲流底层的字节数组也设成32k)

低级流按照字节数组复制(数组长度32k): 1.128s
缓冲流按照字节数组复制(数组长度32k): 1.133s

继续把数组变大,看一看缓冲流就一定性能高吗?现在采用一次读取1024*46个字节数据试试

低级流按照字节数组复制(数组长度64k): 1.039s
缓冲流按照字节数组复制(数组长度64l): 1.151s

此时你会发现,当数组大到一定程度,性能已经提高不了多少了,甚至缓冲流的性能还没有低级流高。
在实际开发中,想提升读写性能就扩大数组大小,大小取决于经验,并且缓冲流的性能不一定就比低级流好。

相关文章:

java IO流(二) 字符流 缓冲流 原始流与缓冲流性能分析

字符流 前面学习的字节流虽然可以读取文件中的字节数据,但是如果文件中有中文,使用字节流来读取,就有可能读到半个汉字的情况,这样会导致乱码。虽然使用读取全部字节的方法不会出现乱码,但是如果文件过大又不太合适。…...

复现XSS漏洞及分析

XSS漏洞概述: 类型一:反射型 类型二:存储型 类型三:DOM型 复现20字符短域名绕过 一、安装BEEF 1、在Kali中运行apt install beef-xss 2、运行beef 3、在浏览器访问 二、安装galleryCMS *遇到一点小问题 提示"last…...

Vue组件之间传值

聊一聊vue里面组件之间的传值 首先总结一下vue里面传值的几种关系: 如上图所示, A与B、A与C、B与D、C与F组件之间是父子关系; B与C之间是兄弟关系;A与D、A与E之间是隔代关系; D与F是堂兄关系,针对以上关系 我们把组件…...

windows查看端口占用,通过端口找进程号(查找进程号),通过进程号定位应用名(查找应用)(netstat、tasklist)

文章目录 通过端口号查看进程号netstat通过进程号定位应用程序tasklist 通过端口号查看进程号netstat 在Windows系统中,可以使用 netstat 命令来查看端口的占用情况。以下是具体的步骤: 打开命令提示符(CMD):按WinR组…...

Weblogic SSRF【漏洞复现】

文章目录 漏洞测试注入HTTP头,利用Redis反弹shell redis不能启动问题解决 Path : vulhub/weblogic/ssrf 编译及启动测试环境 docker compose up -dWeblogic中存在一个SSRF漏洞,利用该漏洞可以发送任意HTTP请求,进而攻击内网中redis、fastcgi…...

文件读取漏洞复现(Metinfo 6.0.0)

文章目录 安装环境启动环境漏洞复现代码审计 安装环境 安装phpstudy,下载MetInfo 6.0.0版本软件,复制到phpstudy目录下的www目录中。 打开phpstudy,访问浏览器127.0.0.1/MetInfo6.0.0/install/index.php,打开Meinfo 6.0.0主页&a…...

【工程实践】使用git clone 批量下载huggingface模型文件

前言 经常需要下载模型到服务器,使用git clone方法可以快速实现模型下载。 1.选定要下载的模型 以下载moka-ai/m3e-base为例,切换到Files and versions。 2.更改下载网页的url 如上图所示,当前要下载模型网页的url为: https://hu…...

2020 杭电多校第三场 H Triangle Collision(反射套路 + 绕点旋转 + 矢量

2020 杭电多校第三场 H. Triangle Collision(反射套路 绕点旋转 矢量分解) 大意:给出一个等边三角形 , 以底边中线建立坐标系 , 给出三角形中一点 , 和其初始速度 , 小球在等边三角形中做完全弹性碰撞 , …...

Servlet属性、监听者和会话

没有servlet能单独存在。在当前的现代Web应用中,许多组件都是在一起协作共同完成一个目标。怎么让这些组件共享信息?如何隐藏信息?怎样让信息做到线程安全? 1 属性和监听者 1.1 初始化 容器初始化一个servlet时,会为…...

Gin学习记录2——路由

路由 一. 常规路由二. 动态路由三. 带参数的路由3.1 GET3.2 POST3.3 绑定 四. 简单的路由组五. 文件分组 一. 常规路由 package mainimport ("net/http""github.com/gin-gonic/gin" )func index(ctx *gin.Context) {ctx.String(http.StatusOK, "Hell…...

《计算机算法设计与分析》第一章:算法概述

第一章 算法概述 1.1 算法复杂性分析 公共标准:渐进时间复杂度 (1)大O表示法: 例如: 大O表示法和前面的最坏时间复杂度的区别在于:大O表示法表示的更为简洁, 而最坏时间复杂度相对就比较繁琐&am…...

华为数通方向HCIP-DataCom H12-821题库(单选题:201-220)

第201题 BGP 协议用​​ beer default-route-advertise​​ 命令来给邻居发布缺省路由,那么以下关于本地 BGP 路由表变化的描述,正确的是哪一项? A、在本地 BGP 路由表中生成一条活跃的缺省路由并下发给路由表 B、在本地 BGP 路由表中生成一条不活跃的缺省路由&…...

使用ELK收集解析nginx日志和kibana可视化仪表盘

文章目录 ELK生产环境配置filebeat 配置logstash 配置 kibana仪表盘配置配置nginx转发ES和kibanaELK设置账号和密码 ELK生产环境配置 ELK收集nginx日志有多种方案,一般比较常见的做法是在生产环境服务器搭建filebeat 收集nginx的文件日志并写入到队列(k…...

【Sentinel】ProcessorSlotChain处理器插槽链与Node

文章目录 1、Sentinel的基本概念2、ProcessorSlotChain3、Node 1、Sentinel的基本概念 Sentinel实现限流、隔离、降级、熔断等功能,本质要做的就是两件事情: 统计数据:统计某个资源的访问数据(QPS、RT等信息)规则判断…...

数据库管理系统(DBMS)的事务四大特性(ACID)以及事务的四种隔离级别

一、什么是ACID? ACID是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability) 的缩写,是在可靠数据库管理系统(DBMS&…...

leetcode 234. 回文链表

2023.9.5 本题先将链表的节点值移到数组中,再用双指针去判断该数组是否为回文的即可。 代码如下: /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* …...

Scala集合继承体系图

Scala集合简介 1) Scala 的集合有三大类:序列 Seq、集Set、映射 Map,所有的集合都扩展自 Iterable特质。 2) 对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两个包 不可变集合…...

《Go 语言第一课》课程学习笔记(十五)

并发 Go 的并发方案:goroutine 并行(parallelism),指的就是在同一时刻,有两个或两个以上的任务(这里指进程)的代码在处理器上执行。 并发不是并行,并发关乎结构,并行关…...

练习 Qt 实时显示鼠标坐标位置

Qt 入门实战教程(目录) 前驱课程 本文是文章 Qt鼠标点击事件处理:显示鼠标点击位置(完整示例) 的一个作业(下文称之为“前驱课程”)。 前驱课程中,我们完整的展示了如何在QtCreat…...

Leetcode130. 被围绕的区域

Every day a Leetcode 题目来源:130. 被围绕的区域 本题给定的矩阵中有三种元素: 字母 X;被字母 X 包围的字母 O;没有被字母 X 包围的字母 O。 本题要求将所有被字母 X 包围的字母 O都变为字母 X ,但很难判断哪些 …...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

基于 TAPD 进行项目管理

起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...