当前位置: 首页 > 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 ,但很难判断哪些 …...

6.xpath的基本使用

xpath是python做数据解析的库 目录 1 安装 2 解析本地的html文件 2.1 只有一个标签的情况 2.2 有多个标签的情况 3 解析网上的页面 4 xpath表达式 4.1 绝对路径 4.2 两个斜杠表示中间隔了0级或多级 4.3 通过属性查找 4.4 通过索引查找 4.5 获取文本内容…...

uniapp组件库总结笔记

uView-ui uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-app UI 框架 优点:整体样式风格不错 缺点:不支持vue3(可以使用社区维护的uview-plus uview-plus 3.0 - 全面兼容nvue的uni-app生态框架 - uni-app UI框架) uni-u…...

day-42 代码随想录算法训练营 动态规划 part 04

416.分割等和子集 分析:需要总和能分成两半,并且有子集能装满一半 思路: 1.dp存储:容量为j时装入的最大数值和dp[j]2.dp[j]max(dp[j],dp[j-nums[i]]nums[i]) 3.全部初始化为04.遍历顺序:外层遍历元素,内…...

Swift 周报 第三十六期

文章目录 前言新闻和社区消息称苹果公司和印度财政部官员磋商,扩大在印度的制造产能iPhone 15 Pro 机型新增泰坦灰iPhone 15 全系配 USB-C 苹果拒绝接口和安卓互通 提案正在审查的提案 Swift论坛推荐博文话题讨论关于我们 前言 本期是 Swift 编辑组整理周报的第三十…...

手写Mybatis:第19章-二级缓存

文章目录 一、目标:二级缓存二、设计:二级缓存三、实现:二级缓存3.1 工程结构3.2 二级缓存类图3.3 二级缓存队列3.3.1 FIFI缓存策略3.3.2 事务缓存3.3.3 事务管理3.3.4 修改一级缓存 3.4 缓存执行器3.4.1 执行器接口3.4.2 执行器抽象基类3.4.…...

Alibaba Canal 使用记录

项目中使用 canal 来同步数据到 Elasticsearch, 遇到很多问题,做一下记录: 版本问题: 1. 解析binlog出错 ,表现为 limit excceed:xx 目前使用 mariadb 10.9.7/10.10.6 canal 1.1.6 hotfix ,在这个版本组…...

GIT实战篇,教你如何使用GIT可视化工具

系列文章目录 手把手教你安装Git,萌新迈向专业的必备一步 GIT命令只会抄却不理解?看完原理才能事半功倍! 快速上手GIT命令,现学也能登堂入室 GIT实战篇,教你如何使用GIT可视化工具 系列文章目录一、GIT有哪些常用工具…...

lv3 嵌入式开发-4 linux shell命令(文件搜索、文件处理、压缩)

目录 1 查看文件相关命令 1.1 常用命令 1.2 硬链接和软链接 2 文件搜索相关命令 2.1 查找文件命令 2.2 查找文件内容命令 2.3 其他相关命令 3 文件处理相关命令 3.1 cut 3.2 sed 过滤 3.3 awk 匹配 4 解压缩相关命令 4.1 解压缩文件的意义 4.2 解压缩相关命令 1 …...

SpringBoot2.0集成WebSocket,多客户端

适用于单客户端,一个账号登陆一个客户端,登陆多个客户端会报错 The remote endpoint was in state [TEXT_FULL_WRITING] 这是因为此时的session是不同的,只能锁住一个session,解决此问题的方法把全局静态对象锁住,因…...

华为OD机试 - 等和子数组最小和 - 深度优先搜索(Java 2022 Q4 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷)》…...