背景

在写这篇随笔之前,已经写了io流函数略解(java_File)(一),主要是总结了File的一些操作,以及一些源码介绍。

在Io实际应用中,实际上运用在如果会操作File,实际上很难写出一点能实际应用的code,因为操作文件嘛,更多的是操作流,也就是steam。

下面将简单总结一些流的概念,以及流的一些基本理论,同时也会贴出源码来略看。

实践

io之所以叫io,i的意思是input,o的意思是output,也就是一个输入一个输出,分别对应read与write。

inputsteam

inputsteam 在java 中是一个abstract class。那么它和接口是不一样的,抽象类是可以有具体方法的甚至构造函数。

inputsteam是read操作,那么看下在inputsteam有什么read的函数吧。

/**
* Reads the next byte of data from the input stream. The value byte is
* returned as an <code>int</code> in the range <code>0</code> to
* <code>255</code>. If no byte is available because the end of the stream
* has been reached, the value <code>-1</code> is returned. This method
* blocks until input data is available, the end of the stream is detected,
* or an exception is thrown.
*
* <p> A subclass must provide an implementation of this method.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @exception IOException if an I/O error occurs.
*/
public abstract int read() throws IOException;

read 没有实现,是一个抽象的方法。但是告诉了我们很有用的信息。

如下:

  1. 返回的是一个字节,返回是0-255。为什么是0-255呢?因为一个字节是8位,11111111不就是255嘛。

  2. 如果没有了,则返回-1,为什么会返回-1,因为-1最高效。解释起来很复杂,可以关注我后面总结的数据结构。

  3. 如果错误会返回一个IOException 异常。

同样,我找到了另外一个read

public int read(byte b[], int off, int len) throws IOException {
//判断参数是否符合,比如说byte是否为空,然后off与len的一些基本要求,比如说一个正常的off肯定要>0,然后len>0,len还有大于b.length-off
//在看到 b.length - off的时候就可以确定off是针对b[]的,冲off开始,给b[]写入或者替换数据。
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;
}
//为什么要单独写一个呢?一个是优化,不需要构造for循环,第二个是可以提前检查read错误
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
//for 循环读取,然后read -1则说明到底了。
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}

这个我就不贴注释了,有源码看啥注释。一些关键点,我也给了自己的一些看法。

然后还有一个是:

public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}

其实就是调用read(byte b[], int off, int len);

至此,read部分就基本在这了,当然有其他函数了,不可能一一来说明,用到的时候自然就ok的。

FileInputStream

我们在inputsteam有了一个大体的框架,然而呢,read没有实现。那么来看看到底是如何读取文件的吧,FileInputStream。

依然我们来看read:

public int read() throws IOException {
return read0();
}
private native int read0() throws IOException;

出现了native,这表示是调用外部库。native解释起来有一丢丢麻烦,就是去调用不是java写的库了,例如调用c语言写的函数库,后面也写一片总结吧。

好吧,read只能暂时介绍到这里,操作一下吧。

 try(InputStream inputStream= new FileInputStream("xxxx"))
{
int n;
while ((n=inputStream.read())!=-1) {
System.out.println(n); }
}catch (Exception e) {
// TODO: handle exception
}

ps:

try(InputStream inputStream= new FileInputStream("xxxx"))这样写自动在finally中帮我们调用close方法,因为InputStream 继承了java.lang.AutoCloseable 接口。
为什么要close呢?因为要释放资源啊,用完就放,轻装前行。

ByteArrayInputStream

这个从字面意思是字节数组输入流?意思就是把字符数组转换成InputStream。

例如:

public void ByteArrayInputStreamTest() throws IOException  {
byte[] data={11,12,15,16};
try(InputStream inputStream=new ByteArrayInputStream(data))
{
int n;
while ((n = inputStream.read()) != -1) {
}
}
}

来看看源码实现吧:

1.看看它的超类

ByteArrayInputStream extends InputStream

这就解释了为什么可以这样写:

InputStream inputStream=new ByteArrayInputStream(data)

2.实例化:

public ByteArrayInputStream(byte buf[]) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
}

在这里我们可以想到read(byte b[], int off, int len),其实就是模拟把文件中所有的字节都读出来了,然后给了里面的一个buf 缓存属性。

Reader

InputStream 关于字节流的,Reader 是关于字符流的。

我们知道字节是byte,字符是char,两者存在千丝万缕的关系,他们中间的桥梁是编码。编码又是一个相当难以用一两句话解释的东西了,后续会添加一篇编码的随笔。

总之,看下Reader 到底干什么的吧。

// 读取单个字符
public int read() throws IOException {
char cb[] = new char[1];
if (read(cb, 0, 1) == -1)
return -1;
else
return cb[0];
}
// 抽象没得实现
abstract public int read(char cbuf[], int off, int len) throws IOException;
//调用了抽象read(char cbuf[], int off, int len)
public int read(char cbuf[]) throws IOException {
return read(cbuf, 0, cbuf.length);
}

好吧,没有什么具体的实现,那么就去看看InputStreamReader吧,它的一个实现类。

InputStreamReader

根据上文,我们迫切需要知道的是abstract public int read(char cbuf[], int off, int len) throws IOException的实现方法。

public int read(char[] cbuf,
int offset,
int length) throws IOException {
int off = offset;
int len = length;
synchronized (lock) {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}
if (len == 0)
return 0;
int n = 0;
if (haveLeftoverChar) {
// Copy the leftover char into the buffer
cbuf[off] = leftoverChar;
off++; len--;
haveLeftoverChar = false;
n = 1;
if ((len == 0) || !implReady())
// Return now if this is all we can produce w/o blocking
return n;
}
if (len == 1) {
// Treat single-character array reads just like read()
int c = read0();
if (c == -1)
return (n == 0) ? -1 : n;
cbuf[off] = (char)c;
return n + 1;
}
return n + implRead(cbuf, off, off + len);
}
}

关键部分:

int c = read0();
if (c == -1){
return (n == 0) ? -1 : n;
}
cbuf[off] = (char) c;

上文中提及到read0()是读取一个字节,然后把字节转换成字符。

ok,那么我们就知道原理了。

实践一下吧:

public void readFile() throws IOException {
try (Reader reader = new FileReader("xxxx")) {
char[] buffer = new char[1000];
int n;
while ((n = reader.read(buffer)) != -1) {
}
}
}

CharArrayReader与StringReader

简单说明一下他们俩吧。

char[] test={'a','b'};
try (Reader reader = new CharArrayReader(test)) {
}
try (Reader reader = new StringReader("xxx")) {
}

就是把字符数组或者字符串专成了Reader。

以CharArrayReader为例:

1.继承:

public class CharArrayReader extends Reader

2.实例化

public CharArrayReader(char buf[]) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
}

3.读取

public int read() throws IOException {
synchronized (lock) {
ensureOpen();
if (pos >= count)
return -1;
else
return buf[pos++];
}
}

就是模拟了假如全部的读取文件中的所有数据,然后转换成了char[],缓存起来。

总结

1.不管是一次性读取byte[]还是一个一个读byte,原理上都是一个一个读的,只是byte[] 存储起来了。

2.读取字符流其实是在读取字节后转换的。

3.避免忘记close,推荐使用try(){}这种语法。

4.对于像ByteArrayInputStream 这样的转换,其实是假设数据全部读取出来了,然后进行操作。

io流函数略解(java_input流)[二]的更多相关文章

  1. io流函数略解(java)[一]

    背景 最近在做安卓的过程中,因为im app经常涉及到读取与写入的io问题,所以总结一下.下文使用的是java语言. 实践 材料: java eclipse 1.File 在操作系统中我们一般能看到的 ...

  2. Java IO编程全解(二)——传统的BIO编程

    前面讲到:Java IO编程全解(一)——Java的I/O演进之路 网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口 ...

  3. java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET

    java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET 亲,“社区之星”已经一周岁了!      社区福利快来领取免费参加MDCC大会机会哦    Tag功能介绍—我们 ...

  4. JAVA IO 类库详解

    JAVA IO类库详解 一.InputStream类 1.表示字节输入流的所有类的超类,是一个抽象类. 2.类的方法 方法 参数 功能详述 InputStream 构造方法 available 如果用 ...

  5. Java IO编程全解(四)——NIO编程

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7793964.html 前面讲到:Java IO编程全解(三)——伪异步IO编程 NIO,即New I/O,这 ...

  6. IO(Input Output)流__字符流

    一.IO流简述------用于操作数据的 IO流用来处理设备之间的数据传输; Java对数据的操作是通过流的方式; Java用于操作流的对象都是在IO包中; 流按操作数据分为: 字节流(通用)和字符流 ...

  7. java中的io系统详解(转)

    Java 流在处理上分为字符流和字节流.字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符.字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组. Java 内用 U ...

  8. Java IO编程全解(一)——Java的I/O演进之路

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7419117.html JDK1.4之前的早期版本,Java对I/O的支持并不完善,开发人员在开发高性能I/O ...

  9. Java IO编程全解(三)——伪异步IO编程

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7723174.html 前面讲到:Java IO编程全解(二)--传统的BIO编程 为了解决同步阻塞I/O面临 ...

随机推荐

  1. java本地缓存

    1.为什么要使用缓存 由于服务器.数据库.网络等资源有限,无法支撑越来越多的请求与计算量,所以将一部分数据放在缓存中,以此减小薄弱环节的计算量和请求流程. 网站中缓存的应用场景:        1:可 ...

  2. nyoj 169-素数 (打表)

    169-素数 内存限制:64MB 时间限制:3000ms 特判: No 通过数:42 提交数:84 难度:1 题目描述: 走进世博园某信息通信馆,参观者将获得前所未有的尖端互动体验,一场充满创想和喜悦 ...

  3. docker入门篇

    在网上的教程中,大多数是建议利用linux来安装docker,在此我也建议大家用linux安装,为什么?请看下图 docker使用go语言开发,并且运行在linux系统下,而如果想用window运行, ...

  4. JMeter从0开始-笔记

    1.安装Jmeter之前 安装Jmeter之前需要先配置Java环境,我们下载的是jmeter4.0,所以java版本最好是选用java8以上的版本. 安装JDk1.6的步骤如下: 点击下载的JDK文 ...

  5. Java多线程——多线程方法详解

    本系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线程的深入剖 ...

  6. [FPGA]Verilog实现寄存器LS374

    目录 想说的话... 正文 IC介绍 电路连接图 功能表 逻辑图 实验原理 单元实现_D触发器 整体实现(完整代码) 想说的话... 不久前正式开通了博客,以后有空了会尽量把自己学习过程中的心得或者感 ...

  7. sqlalchemy 源码分析之create_engine引擎的创建

    引擎是sqlalchemy的核心,不管是 sql core 还是orm的使用都需要依赖引擎的创建,为此我们研究下,引擎是如何创建的. from sqlalchemy import create_eng ...

  8. 【Luogu 1993】差分约束系统问题——小K的农场

    Luogu P1993 前置知识:最短路径相关算法 如果一个系统由n个变量和m个约束条件组成,形成m个形如ai-aj≤k的不等式(i,j∈[1,n],k为常数),则称其为差分约束系统. 显然题目中给出 ...

  9. 图解 Spring:HTTP 请求的处理流程与机制【5】

    5. HTTP 请求处理相关配置文件说明 HTTP 请求穿越的整个空间是分层的,包括:Web 容器.Web 应用.Spring 框架等,它们每层都是通过配置文件配置初始化的,这是一种松耦合的架构设计. ...

  10. setBounds方法,与setLayout(null)

    首先把相关容器的布局方式设为 setLayout(null); 然后调用组件的  setBounds() 方法 设置button的位置为(100,100) 长宽分别为 60,25 jButton.se ...