java 提供了读写缓存api。
byte:java.io.BufferedInputStream 、 java.io.BufferedOutputStream
char: java.io.BufferedReader、java.io.BufferedWriter
好处:
1、可以避免一次性写入大量的数据,这样可能瞬间造成内存占用太多,导致系统不稳定。
2、可以对写入较少的数据进行缓冲,避免写入输入承载终端太过频繁。
缺点:几乎没有。
所以几乎任何时候我们都有必要使用缓存的流进行包装。
记得刚学习java io时,听到缓存,感觉很神秘。其实java提供的缓存实现的数据结构就是数组,java 缓存 api都是建立在byte[] 和 char[]基础之上的,也即是:先write(read) 数据到 byte[](char[])里,然后一旦缓存数据满,再一次性读取(写入)。
源码分析:
package java.io;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
/**
* BufferedInputStream 继承自 FilterInputStream,所以其本身需要一个 internal InputStream 来承载数据的读取源头
* 其缓存实现的本质是:byte[] 对数据的缓存。
*/
public class BufferedInputStream extends FilterInputStream {
private static int defaultBufferSize = 8192;
/**
* 缓存数据存储的地方,必要时候可以改变大小(当然也不是原来的buf数组了)
*/
protected volatile byte buf[];
/**
* Atomic updater to provide compareAndSet for buf. This is
* necessary because closes can be asynchronous. We use nullness
* of buf[] as primary indicator that this stream is closed. (The
* "in" field is also nulled out on close.)
*/
private static final
AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
AtomicReferenceFieldUpdater.newUpdater
(BufferedInputStream.class, byte[].class, "buf");
/**
* 缓存的有效字节数
*/
protected int count;
/**
* 下一个可读的字节在数组中的位置
*/
protected int pos;
/**
* 最近一次mark的位置
*/
protected int markpos = -1;
/**
* The maximum read ahead allowed after a call to the
* <code>mark</code> method before subsequent calls to the
* <code>reset</code> method fail.
* Whenever the difference between <code>pos</code>
* and <code>markpos</code> exceeds <code>marklimit</code>,
* then the mark may be dropped by setting
* <code>markpos</code> to <code>-1</code>.
*
* @see java.io.BufferedInputStream#mark(int)
* @see java.io.BufferedInputStream#reset()
*/
protected int marklimit;
/**
*底层的流是否已关闭
*/
private InputStream getInIfOpen() throws IOException {
InputStream input = in;
if (input == null)
throw new IOException("Stream closed");
return input;
}
private byte[] getBufIfOpen() throws IOException {
byte[] buffer = buf;
if (buffer == null)
throw new IOException("Stream closed");
return buffer;
}
public BufferedInputStream(InputStream in) {
this(in, defaultBufferSize);
}
public BufferedInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
/**
* Fills the buffer with more data, taking into account
* shuffling and other tricks for dealing with marks.
* Assumes that it is being called by a synchronized method.
* This method also assumes that all data has already been read in,
* hence pos > count.
*/
private void fill() throws IOException {
byte[] buffer = getBufIfOpen();
if (markpos < 0) //如果没有设置mark,那么pos的位置设置为0。(因为没有mark,算是全部读取新数据)
pos = 0; /* no mark: throw away the buffer */
else if (pos >= buffer.length) /* 缓冲里没有空闲空间,并且有mark设置 */
if (markpos > 0) { /* 此种情况必须保留markpos之后的数据 */
int sz = pos - markpos;
System.arraycopy(buffer, markpos, buffer, 0, sz);
pos = sz; //pos 在新的buffer里的位置是sz
markpos = 0; //markpos 在新的buffer里面为 0,所以必须需要设置为0
} else if (buffer.length >= marklimit) { //出错啦,这种情况不该出现的
markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */
} else { /* 增长buffer */
int nsz = pos * 2;
if (nsz > marklimit)//但是不能超过marklimit
nsz = marklimit;
byte nbuf[] = new byte[nsz];
System.arraycopy(buffer, 0, nbuf, 0, pos);
if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
// Can't replace buf if there was an async close.
// Note: This would need to be changed if fill()
// is ever made accessible to multiple threads.
// But for now, the only way CAS can fail is via close.
// assert buf == null;
throw new IOException("Stream closed");
}
buffer = nbuf;
}
count = pos;
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
count = n + pos;
}
/**
* 读取一个字节
*/
public synchronized int read() throws IOException {
if (pos >= count) {//如果到了缓冲的最大索引位置,那么去fill数据
fill();
if (pos >= count) //fill之后如果pos>=count,那么说明 underlying stream 里已经没有数据
return -1;
}
return getBufIfOpen()[pos++] & 0xff; //正常返回
}
/**
* Read characters into a portion of an array, reading from the underlying
* stream at most once if necessary.
*/
private int read1(byte[] b, int off, int len) throws IOException {
int avail = count - pos;
if (avail <= 0) {
if (len >= getBufIfOpen().length && markpos < 0) { //如果没有多余的缓存数据,并且没有设置mark标记,并且流里剩余的数据不足len长度,那么直接从数据流里读取,直接返回。
return getInIfOpen().read(b, off, len);
}
fill(); //其他情况则去填充数据
avail = count - pos; //查看缓存中剩下的数据
if (avail <= 0) return -1; //如果缓存里没有新数据(即:fill没有添加新数据)。
}
int cnt = (avail < len) ? avail : len; //取剩下的数据和len的较小值
System.arraycopy(getBufIfOpen(), pos, b, off, cnt); //把数据读取 到b数组里。
pos += cnt;//改变当前字节的位置
return cnt;
}
/**
* 读取流数据到b数组里,从b[off]开始放数据,长度为len
*/
public synchronized int read(byte b[], int off, int len)throws IOException
{
getBufIfOpen(); // Check for closed stream
if ((off | len | (off + len) | (b.length - (off + len))) < 0) { //如果 off<0 或者 len <0 或者 (off + len) <0 或者 b.length - (off + len) <0
throw new IndexOutOfBoundsException();
} else if (len == 0) { //len =0,直接返回
return 0;
}
int n = 0; //记录已经读到的总byte数
for (;;) {
int nread = read1(b, off + n, len - n);
if (nread <= 0) //如果没有读到数据,那么直接返回
return (n == 0) ? nread : n;
n += nread;
if (n >= len) //如果已经到len 那么返回n(注意:事实上n=len,而不会n>len)
return n;
// if not closed but no bytes available, return
InputStream input = in;
if (input != null && input.available() <= 0) //每次读过之后判断 input 是否还有多余的可读,如果没有那么直接返回
return n;
}
}
/**
* 跳过n字节
*/
public synchronized long skip(long n) throws IOException {
getBufIfOpen(); // Check for closed stream
if (n <= 0) {
return 0;
}
long avail = count - pos;
if (avail <= 0) { //如果缓存的数据已读完
// If no mark position set then don't keep in buffer
if (markpos <0) //如果没有设置mark,那么直接调用 underlying stream 的skip方法
return getInIfOpen().skip(n);
// 填充数据
fill();
avail = count - pos;
if (avail <= 0) //如果avail<=0,说明underlying stream 中也没有剩余数据
return 0;
}
long skipped = (avail < n) ? avail : n; //最avail 和 n 的最小值
pos += skipped; //调整pos 是skip方法的本质
return skipped;
}
/**
* 返回可以的字节数。
* <p>
* This method returns the sum of the number of bytes remaining to be read in
* the buffer (<code>count - pos</code>) and the result of calling the
* {@link java.io.FilterInputStream#in in}.available().
*
* @return an estimate of the number of bytes that can be read (or skipped
* over) from this input stream without blocking.
* @exception IOException if this input stream has been closed by
* invoking its {@link #close()} method,
* or an I/O error occurs.
*/
public synchronized int available() throws IOException {
return getInIfOpen().available() + (count - pos);
}
/**
* 打标记
* markpos:把当前位置记录为标记
* readlimit:在mark变的无线之前运行读取的最大字节数
*/
public synchronized void mark(int readlimit) {
marklimit = readlimit;
markpos = pos;
}
/**
* 重置操作。
* 如果没有mark过,调用reset方法会抛出:IOException
*
*/
public synchronized void reset() throws IOException {
getBufIfOpen(); // Cause exception if closed
if (markpos < 0)
throw new IOException("Resetting to invalid mark");
pos = markpos; //重置的效果是:下一次read读取继续从上次打标记的地方读取。
}
/**
* 支持回溯操作
*/
public boolean markSupported() {
return true;
}
/**
* 关闭此流,并释放与此流相关的任何系统资源
* 一旦close流后,任何 read(), available(), reset()将抛出异常
*/
public void close() throws IOException {
byte[] buffer;
while ( (buffer = buf) != null) {
if (bufUpdater.compareAndSet(this, buffer, null)) { //将buf设置为空,如果失败则循环知道buf 为空为止。因为close 不是线程安全的,所以适用原子类bufUpdater 配合操作。
InputStream input = in;
in = null;
if (input != null)
input.close();
return;
}
// Else retry in case a new buf was CASed in fill()
}
}
}
分享到:
相关推荐
在Java IO类库中,装饰器模式被广泛使用,以灵活地扩展类的功能,而避免了使用继承带来的复杂性。装饰器模式的核心在于,它定义了一个与组件接口相同的接口,因此可以在运行时动态地将责任附加到对象上。 在Java IO...
标签 "源码" 暗示这篇博客可能深入剖析了 `InputStream` 类的源代码,分析了其实现细节和设计思路。这可能包括类的构造函数、方法的实现逻辑以及与其他类的协作关系。 "工具" 标签可能意味着博客作者讨论了如何利用...
模板模式是一种行为设计模式,它在Java编程中...它在Java的多种场景中都有应用,包括IO流、Web服务和测试框架等,是理解和掌握设计模式的关键之一。通过熟练运用模板模式,开发者可以编写出更加灵活、易于维护的代码。
JESD79-2F DDR2 JESD79-3F DDR3 JESD79-4D DDR4 JESD79-5C DDR5 JESD209-2F LPDDR2 JESD209-3C LPDDR3 JESD209-4E LPDDR4 JESD209-4-1A LPDDR4X JESD209-5C LPDDR5(X)
COMSOL二维光子晶体角态研究:单胞与超胞能带计算及边界态与角态特性分析,COMSOL二维光子晶体角态研究:单胞与超胞能带计算及边界态与角态特性分析,comsol二维光子晶体角态。 单胞能带,超胞能带,边界态以及角态计算。 ,comsol;二维光子晶体;角态;单胞能带;超胞能带;边界态计算,基于Comsol的二维光子晶体角态及能带边界计算研究
六自由度机械臂抓取动作仿真与代码解析:抓取动画、关节参数变化及轨迹图解详解,六自由度机械臂抓取动作仿真指南:掌握两套代码实现动画与轨迹图模拟学习攻略,六自由度机械臂抓取动作仿真-8 两套关于抓取动作的代码,包括抓取动画、关节角、角速度、角加速度的变化仿真、以及抓取轨迹图 简单易懂好上手~ ,六自由度机械臂;抓取动作仿真;抓取动画;关节角变化;角速度角加速度;抓取轨迹图;两套代码;简单易懂好上手,六自由度机械臂抓取动作仿真演示:代码与轨迹图解
ITC网络广播工具软件
Multisim四位密码锁电路仿真设计:设定、开锁与声光报警功能演示资料包,Multisim四位密码锁电路仿真设计:设定、输入、开锁与报警功能详解,附源文件、原理说明书与演示视频,multisim四位密码锁电路仿真设计 功能: 1.通过拨码开关1进行初始密码设定。 2.通过拨码开关2输入密码,实现开锁判断。 3.如果密码正确,LED绿灯亮,表示开锁。 4.如果密码不正确,LED红灯亮,蜂鸣器鸣叫,声光报警。 资料包含:仿真源文件+原理说明书+演示视频 ,四位密码锁电路、Multisim仿真设计、初始密码设定;拨码开关输入;开锁判断;LED灯显示;声光报警;仿真源文件;原理说明书;演示视频,Multisim四位密码锁电路仿真设计:初始密码设置与智能解锁功能的声光报警展示
俗话说,摸鱼摸的好,上班没烦恼,毕竟谁能拒绝带薪拉屎呢(手动狗头) 这是一个云开发职场打工人专属上班摸鱼划水微信小程序源码,没有后台 直接导入微信开发者工具即可运行,UI简约大气漂亮,只需登录微信公众平台配置完合法域名即可轻松上线。 用户进入摸鱼小程序,可以自由设置薪资,上班时间、下班时间、发薪日、 月工作天数以提醒自己摸鱼,全民打酱油,让自己成为摸鱼冠军,《商鞅摸鱼哲学》 摸鱼不是自我放纵,而是个人实力的积蓄,我们的小目标是晚睡晚起 小程序中的今日待办会提醒用户带薪拉屎和闲逛,下方展示的是距离休息日的天数,距离下一次发工资的天数和节日的天数。
【毕业设计】基于Java的开发的一个集合校园二手交易、拼车、失物招领等功能的app_pgj
个人记录:PICkit3离线烧录流程 使用软件:MPLAB X IDE v5.30 记录时间:20250215
基于Matlab代码的电力系统状态估计与实验仿真研究:扩展卡尔曼滤波和无迹卡尔曼滤波在电力系统动态状态估计中的应用及效果分析,Matlab仿真实验研究:基于扩展卡尔曼滤波器与无迹卡尔曼滤波器对电力系统状态估计的影响及验证,状态估计 电力系统状态估计 Matlab代码 实验仿真研究 电力系统由于测量值和传输误差,还有测量噪声的影响,会对状态估计产生影响。 因此,需要对嘈杂的测量进行滤波,以获得准确的电力系统运行动态。 本文使用扩展卡尔曼滤波器(EKF)和无迹卡尔曼滤波器(UKF)来估计电力系统的动态状态。 扩展卡尔曼滤波EKF、无迹卡尔曼滤波UKF 利用扩展的无迹卡尔曼滤波器估计了动力系统的动态状态。 对WECC 3机9总线系统和新英格兰10机39总线系统进行了案例研究。 结果表明EKF和UKF都能准确地估计电力系统的动态状态。 ,核心关键词:状态估计; 电力系统状态估计; Matlab代码; 实验仿真; 测量值误差; 测量噪声; 扩展卡尔曼滤波器(EKF); 无迹卡尔曼滤波器(UKF); 动力系统; 动态状态估计; WECC 3机9总线系统; 新英格兰10机39总线系统。,Matlab
springboot在线考试--
台达DVP EH3与MS300 PLC&变频器通讯程序的全面解决方案,台达DVP EH3与MS300通讯程序:稳定可靠的频率控制与启停管理系统,台达DVP EH3与台达MS300通讯程序(TDEH-9) 可直接用于实际的程序,程序带注释,并附送触摸屏程序,有接线方式和设置,通讯地址说明等。 程序采用轮询,可靠稳定 器件:台达DVP EH3系列PLC,台达MS300系列变频器,昆仑通态7022Ni 功能:实现频率设定,启停控制,实际频率读取,加减速时间设定。 资料:带注释程序,触摸屏程序,接线和设置说明,后续有技术咨询。 ,核心关键词:台达DVP EH3; 台达MS300; 通讯程序(TDEH-9); 轮询; 稳定; 频率设定; 启停控制; 实际频率读取; 加减速时间设定; 触摸屏程序; 接线方式; 设置说明; 技术咨询。,台达PLC与变频器通讯程序(带注释、触摸屏控制)
项目资源包含:可运行源码+sql文件 适用人群:学习不同技术领域的小白或进阶学习者;可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。项目具有较高的学习借鉴价值,也可拿来修改、二次开发。 个人账户管理:支持用户注册、登录与个人信息编辑;提供密码找回及账号安全保护措施。 声纹采集:利用麦克风设备录制用户的声纹样本;支持多种录音格式和质量调整,确保采集到清晰、准确的声纹数据。 声纹模板库管理:建立和维护一个安全的声纹模板库;支持声纹模板的添加、删除、更新和查询操作。 声纹比对与识别:运用深度学习算法对输入的声纹数据进行特征提取和匹配;实现快速、准确的声纹身份验证。 多场景应用支持:适用于多种场景,如门禁系统、移动支付、远程登录等;可根据实际需求定制开发相应的应用场景。 实时监控与报警:实时监控系统运行状态,包括声纹识别成功率、处理速度等指标;当出现异常情况时,及时发出报警信息。 数据分析与报告生成:收集并分析声纹识别过程中的数据,如识别准确率、处理时间等;根据用户需求输出包含详细图表说明的专业级文档供下载打印保存。 社区互动交流:设立论坛版块鼓励用户分享心得体会讨论热点话题;定期邀请行业专家举办线上讲座传授实用技巧知识。 音乐筛选与推荐:集成音乐平台API,根据用户的浏览习惯和情绪状态推荐背景音乐,增强用户体验。 数据可视化:提供交互式的数据可视化面板,使非技术用户也能轻松理解复杂的数据集,从而做出更明智的决策。
三相与多相开绕组永磁同步电机仿真模型的先进控制策略探讨与实现,三相与多相开绕组永磁同步电机的Simulink仿真模型与先进控制策略研究,开绕组电机,开绕组永磁同步电机仿真模型、simulink仿真 共直流母线、独立直流母线,两相容错,三相容错控制,零序电流抑制,控制策略很多 三相开绕组永磁同步电机,六相开绕组永磁同步电机 五相开绕组永磁同步电机,五相开绕组电机 ,开绕组电机; 永磁同步电机仿真模型; simulink仿真; 共直流母线; 独立直流母线; 两相容错; 三相容错控制; 零序电流抑制; 控制策略; 六相开绕组永磁同步电机; 五相开绕组永磁同步电机,开绕组电机仿真研究:共直流母线与独立直流母线的容错控制策略
【毕业设计】基于Java的开发的网上汽车租赁管理系统_pgj
csv 模块是 Python 的标准库,无需额外安装。 运行结果如下图: ['姓名', '年龄', '城市'] ['张三', '25', '北京'] ['李四', '30', '上海'] ['王五', '22', '广州']
【毕业设计】基于Java+Springboot+Vue的宠物领养系统_pgj
让前端开发者学习“机器学习”!