我是 啤酒就辣条,一个Java。
学而时习之,不亦说乎?希望通过博客的形式,总结、分享,梳理自己、帮助他人。
另外,啤酒就辣条,味道不错哦~
流的定义
流是一组有序的字节集合,是对数据传输的抽象。流的本质是数据传输,根据传输的特性,流又被分为多种情况。
流的分类
按照数据类型可以分为字符流
和字节流
。
字节流
基本单位是一个字节(8bit),可以处理所有类型的数据。
字符流
基本代为是多个字节(一般是两个字节),一般处理字符数据。字符流
某种意义可以看作,被包装过的字节流
。因为字符流
是基于字节流
读取之后,查了特定的码表,进行字符转换的。所以,如果是字符类型的数据传输,首先使用字符流
,其他传输使用字节流。
按照输入输出方向可分为输入流
和输出流
。输入流
只能进行读操作。输出流
只能进行写操作。
Java种的类
根据流的分类,可得字节输入流,字节输出流,字符输入流,字符输出流
。这四种分类分别对四个抽象类InputStream、OutputStream、Reader、Writer
,Java种所有的IO流类都是继承其一。
字节输入流
InputStream
是所有字节输入流的超类。既然是输入流,肯定会有读的方法read()
/**
* @param b 当前缓存区的数据
* @param off 当前缓存区已写入的位置
* @param len 要读取数据的长度
*/
public int read(byte b[], int off, int len) throws IOException {
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 c = read();
if (c == -1) {
return -1;
}
// 这里可以看出是一个bit位一个bit位读进缓存区的
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
这个方法逻辑很清晰了,首先判断缓存区能不能放下输入的数据,然后以字节为单位读进缓存区。
还有个方法是跳过或者丢弃输入流的前n个字节,但是结果跳过的字节数可能小于n。
/**
* @param n 要跳过的字节数
*/
public long skip(long n) throws IOException {
long remaining = n;
int nr;
if (n <= 0) {
return 0;
}
int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
byte[] skipBuffer = new byte[size];
while (remaining > 0) {
nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
if (nr < 0) {
break;
}
remaining -= nr;
}
// 请注意此时 remaining 可能不为0。
return n - remaining;
}
还有几个方法:
available()
返回可读字节数的估计值。
close()
关闭字节输入流,并释放相应资源。
mark(int readlimit)
在输入流种标记当前位置。
reset()
将此流重新定位到mark()的位置。
markSupported()
查询此输入流是否支持mark()和reset()方法。
这里主要说明一下mark()和reset()方法。正常情况下,一个流只能读一次。 mark()可以作为标记,某一时刻使用reset()方法让指针重新回到标记处。
字节输出流
OutputStream
是所有字节输入流的超类。既然是输入流,肯定会有读的方法write()
。
主要方法有三个。
write()
将指定的字节转化成输出流。
flush()
将缓存区数据强制刷新出去,刷新到文件或者外设中。
close()
关闭字节输出流,并释放相应资源。
对于InputStream
和OutputStream
提供的方法很多没有带锁,但往往实现的时候都会带上锁。例如往往会加上synchronized
。
字符输入流
Reader
是所有字符输入流的超类。
大部分方法和InputStream
差不多,只是从字节变成了字符。只是Reader
提供了对象级别的锁。
protected Object lock;
protected Reader() {
this.lock = this;
}
字符输出流
Writer
是所有字符输入流的超类。当然,Writer
也提供了对象级别的锁。
protected Object lock;
protected Writer() {
this.lock = this;
}
除此之外,Writer
比OutputStream
多了append()
方法。
append()
方法是数据的追加。
write()
方法是数据的覆盖。