`

PushbackInputStream 源码分析

阅读更多
扩展java.io.FilterInputStream,代表的是可放回输入流。用于根据特定字符来判断流类型或编码等。

1. 内部存储:

protected byte[] buf; // 缓冲区,从底层流获取数据

protected int pos; // 下一个要读取字节的位置

protected volatile InputStream in; // 底层流,继承自FilterInputStream


2. 构造函数:
public PushbackInputStream(InputStream in, int size) {
	super(in);
	if (size <= 0) {
		throw new IllegalArgumentException("size <= 0");
	}
	this.buf = new byte[size];
	this.pos = size;
}

public PushbackInputStream(InputStream in) {
	this(in, 1);
}


3. 读取
// 从缓冲区(+底层流)读取数据,放到指定数组上。返回读取字节的个数。
public int read(byte[] b, int off, int len) throws IOException {
	ensureOpen();
	if (b == null) {
		throw new NullPointerException();
	} else if (off < 0 || len < 0 || len > b.length - off) {
		throw new IndexOutOfBoundsException();
	} else if (len == 0) {
		return 0;
	}

	int avail = buf.length - pos; // 缓冲区可读取字节数
	if (avail > 0) {
		if (len < avail) { // 缓冲区可读取字节数够用
			avail = len; // 给avail赋值,防止len-avail相减为负
		}
		System.arraycopy(buf, pos, b, off, avail); // 读取操作
		pos += avail; // 读取位置后移 avail位
		off += avail; // 偏移值后移 avail位
		len -= avail; // 还需读取字节数
	}
	if (len > 0) { // 还需读取
		len = super.read(b, off, len); // 从底层流读取
		if (len == -1) { // 未读取到数据
			return avail == 0 ? -1 : avail; // avail为0,表示都没有读取到数据;否则为从缓冲区读取数
		}
		return avail + len; // 总读取数 = 从缓冲区读取数 + 从底层流读取数
	}
	return avail; // 从缓冲区读取数
}


4. 放回
public void unread(int b) throws IOException {
	ensureOpen();
	if (pos == 0) { // 缓冲区已满
		throw new IOException("Push back buffer is full");
	}
	buf[--pos] = (byte) b; // 然后读取位置回退,该位置重新设置为原来的值
}


public void unread(byte[] b, int off, int len) throws IOException {
	ensureOpen();
	if (len > pos) { // 缓冲区回退长度不够
		throw new IOException("Push back buffer is full");
	}
	pos -= len; // 回退len个字节
	System.arraycopy(b, off, buf, pos, len); // 将len个字节放回
}


5. 预估剩余可读取字节数
public int available() throws IOException {
	ensureOpen();
	return (buf.length - pos) + super.available(); // 缓冲区可读取数 + 底层可读取数
}


6. 跳过
public long skip(long n) throws IOException {
	ensureOpen();
	if (n <= 0) {
		return 0;
	}

	long pskip = buf.length - pos; // 缓冲区可用存储位置个数
	if (pskip > 0) {
		if (n < pskip) { // 可用个数比跳过个数少
			pskip = n; // pskip赋值为n,防止n -= pskip小于0
		}
		pos += pskip; // 读取位置后移pskip位
		n -= pskip; // 还需跳过数
	}
	if (n > 0) { // 还需跳过n个字节
		pskip += super.skip(n); // 总跳过字节数 = 缓冲区跳过数 + 底层流skip方法跳过数
	}
	return pskip;
}


7. 不支持mark相关的操作
public boolean markSupported() {
	return false;
}

public synchronized void mark(int readlimit) {
}

public synchronized void reset() throws IOException {
	throw new IOException("mark/reset not supported");
}


8. 例子:去除UTF文件的BOM头

BOM (Byte Order Mark),包含三个字节"EF BB BF"。文件的开始位置有这几个字节,表明是UTF文件,读取数据的时候需要忽略它们。

public class BOMCleaner {

	static final Logger LOG = LoggerFactory.getLogger(BOMCleaner.class);
	
	static final int BOM_1 = 0xEF; // BOM第一个字节
	static final int BOM_2 = 0xBB; // BOM第二个字节
	static final int BOM_3 = 0xBF; // BOM第三个字节
	
	public static void main(String[] args) throws IOException {
		FileInputStream fis = new FileInputStream("D:/mine.txt");
		InputStream cleanIs = getInputStreamWithoutBom(fis);
	}

	public static InputStream getInputStreamWithoutBom(InputStream in) throws IOException {
		PushbackInputStream pbIn = new PushbackInputStream(in, 3);
		byte[] bytes = new byte[3];
		int count = pbIn.read(bytes);
		if (count == 3 && (bytes[0] & 0xFF) == BOM_1 && (bytes[1] & 0xFF) == BOM_2 && (bytes[2] & 0xFF) == BOM_3) {
			LOG.debug("变更文件存在BOM头");
		} else {
			pbIn.unread(bytes);
		}

		return pbIn;
	}
}
分享到:
评论

相关推荐

    bytestreamdemo.zip

    java IO 字节流练习代码 FileInputStream和FileOutputStream BufferedInputStream 和 BufferedOutputStream DataInputStream 和 DataOutputStream ObjectInputStream和ObjectOutputStream ...PushbackInputStream

    android 上传文件

    PushbackInputStream inStream = new PushbackInputStream(socket.getInputStream()); String response = StreamTool.readLine(inStream); System.out.println(response); String[] items = response...

    JDK_API_1_6

    PushbackInputStream PushbackInputStream 为另一个输入流添加性能,即“推回 (push back)”或“取消读取 (unread)”一个字节的能力。 PushbackReader 允许将字符推回到流的字符流 reader。 RandomAccessFile 此类...

    Java之IO流学习总结

    PushbackInputStream 的功能是查看最后一个字节,不满意就放入缓冲区。主要用在编译器的语法、词法分析部分。输出部分的BufferedOutputStream 几乎实现相近的功能。 StringBufferInputStream 已经被Deprecated,本身...

    防雷及短路计算软件.zip

    防雷及短路计算软件

    电线穿管选用小软件.zip

    电线穿管选用小软件

    【小白python数据分析入门4Pandas可视化-板块8案例 2018幸福大数据】

    小白python数据分析入门4Pandas可视化——板块8案例 2018幸福大数据,辅助8.1读取数据

    电气照明照度计算软件.zip

    电气照明照度计算软件

    数据库模拟考试试卷试卷

    数据库模拟考试试卷试卷

    AI人工智能算法工程师mk体系课(31周)

    算法是什么 划重点:算法是计算机科学与数学的边界,是一系列解决问题的清晰指令。 1、算法首先是数学的一部分,是子集而非全集只有那些能够被计算机实现的、而且用于解决实际问题的那部分数学内容,才能被纳入“算法”这个范畴,成为计算机科学的一部分,所以对于同一个数学问题,数学更加关心理论上能不能求解,而算法通常更关心是不是可以在有限的时间和空间内使用计算机求解。 2、算法是一系列解决问题的清晰指令就像是总指挥,需要不停地发送指令,一个算法的优劣可以用空间复杂度与时间复杂度来衡量,而算法工程师就是利用算法处理事物的人,因此逻辑完备和思路清晰是最重要的素质,通过这种方式,把想法通过算法的魔法变成“产品”,解决实际工程应用场景中的问题。 算法工程师承担的是整个工程中最核心的思路演绎,如果核心出了纰漏,则整个系统就容易出错,工程问题就得不到解决,1%的差错率都是不能被接受的。

    W25Q512数据手册

    W25Q512数据手册。The W25Q512JV (512M-bit) Serial Flash memory provides a storage solution for systems with limited space, pins and power. The 25Q series offers flexibility and performance well beyond ordinary Serial Flash devices. They are ideal for code shadowing to RAM, executing code directly from Dual/Quad SPI (XIP) and storing voice, text and data. The device operates on a single 2.7V to 3.6V power supply with current consumption as low as 1µA for power-down. All devices are offered in space-

    电学计算软件.zip

    电学计算软件

    五子棋wuziqi2.zip

    五子棋游戏想必大家都非常熟悉,游戏规则十分简单。游戏开始后,玩家在游戏设置中选择人机对战,则系统执黑棋,玩家自己执白棋。双方轮流下一棋,先将横、竖或斜线的5个或5个以上同色棋子连成不间断的一排者为胜。 【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。 【技术】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes

    单片机C语言Proteus仿真实例数码管显示的频率计

    单片机C语言Proteus仿真实例数码管显示的频率计提取方式是百度网盘分享地址

    计算机设计大赛微课类别国赛一等奖作品时光修复-图像的平滑操作视频

    计算机设计大赛微课类别国赛一等奖作品时光修复-图像的平滑操作视频提取方式是百度网盘分享地址

    setuptools-63.1.0.tar.gz

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    Python源码-数学美之太阳花.py

    Python源码-数学美之太阳花

    五子棋对战小游戏appgobang.zip

    五子棋游戏想必大家都非常熟悉,游戏规则十分简单。游戏开始后,玩家在游戏设置中选择人机对战,则系统执黑棋,玩家自己执白棋。双方轮流下一棋,先将横、竖或斜线的5个或5个以上同色棋子连成不间断的一排者为胜。 【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。 【技术】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes

    Java五子棋项目gobang.zip

    五子棋游戏想必大家都非常熟悉,游戏规则十分简单。游戏开始后,玩家在游戏设置中选择人机对战,则系统执黑棋,玩家自己执白棋。双方轮流下一棋,先将横、竖或斜线的5个或5个以上同色棋子连成不间断的一排者为胜。 【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。 【技术】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes

    setuptools-0.9.5.zip

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

Global site tag (gtag.js) - Google Analytics