(最近刚来到简书平台,以前在CSDN上写的一些东西,也在逐渐的移到这儿来,有些篇幅是很早的时候写下的,因此可能会看到一些内容杂乱的文章,对此深感抱歉,以下为正文)
正文
本篇要讲述的是ByteArrayInputStream类和ByteArrayOutputStream类。
首先让我们来看看ByteArrayOutputStream的源码:
ByteArrayOutputStream类
package java.io;
import java.util.Arrays;
public class ByteArrayOutputStream extends OutputStream {
protected byte buf[];
protected int count;
public ByteArrayOutputStream() {
this(32);
}
public ByteArrayOutputStream(int size) {
if (size < 0) {
throw new IllegalArgumentException("Negative initial size: "
+ size);
}
buf = new byte[size];
}
private void ensureCapacity(int minCapacity) {
// overflow-conscious code
if (minCapacity - buf.length > 0)
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = buf.length;
int newCapacity = oldCapacity << 1;
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
buf = Arrays.copyOf(buf, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
public synchronized void write(int b) {
ensureCapacity(count + 1);
buf[count] = (byte) b;
count += 1;
}
public synchronized void write(byte b[], int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) - b.length > 0)) {
throw new IndexOutOfBoundsException();
}
ensureCapacity(count + len);
System.arraycopy(b, off, buf, count, len);
count += len;
}
public synchronized void writeTo(OutputStream out) throws IOException {
out.write(buf, 0, count);
}
public synchronized void reset() {
count = 0;
}
public synchronized byte toByteArray()[] {
return Arrays.copyOf(buf, count);
}
public synchronized int size() {
return count;
}
public synchronized String toString() {
return new String(buf, 0, count);
}
public synchronized String toString(String charsetName)
throws UnsupportedEncodingException
{
return new String(buf, 0, count, charsetName);
}
@Deprecated
public synchronized String toString(int hibyte) {
return new String(buf, hibyte, 0, count);
}
public void close() throws IOException {
}
}
从源码可以看出,该类继承了OutputStream输出流,其中封装了一个byte类型的数组buf作为数据的缓存区,当进行数据写人的时候,数据会不断地写入buf缓存区中,该缓存区默认大小为32字节。每一次写人数据后,都要执行ensureCapacity方法来确定缓存区容量十分能够容纳写入数据,如果不够的时候会执行grow方法,将容量翻倍以适应写入的数据。当写入完成后,我们可以通过toByteArray方法,来获得缓存区数组的一个副本。因为这个特性,我们可以使用ByteArrayOutputStream进行一次性的数据写入。
下面举例说明ByteArrayOutputStream的使用方法:
package ByteArrayIO;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ByteArrayIOTest {
public static void main(String[] args) {
try {
File file = new File("./src/file/test.txt");
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len;
while ((len = fis.read()) != -1) {
baos.write(len);
}
String messages = baos.toString();
System.out.println(messages);
fis.close();
baos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
执行上述代码,可以在控制台看到以下打印:
从打印可以看文件中的所有数据都被存放在了ByteOutputStream中的缓存区中。值得一提的是,ByteArrayOutputStream还介绍到,是否关闭流并不会影响到方法的执行,也就是说,即使流关闭了,数据依然存在。
下面来说说ByteArrayInputStream,首先贴出其源码:
package java.io;
public
class ByteArrayInputStream extends InputStream {
protected byte buf[];
protected int pos;
protected int mark = 0;
protected int count;
public ByteArrayInputStream(byte buf[]) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
}
public ByteArrayInputStream(byte buf[], int offset, int length) {
this.buf = buf;
this.pos = offset;
this.count = Math.min(offset + length, buf.length);
this.mark = offset;
}
public synchronized int read() {
return (pos < count) ? (buf[pos++] & 0xff) : -1;
}
public synchronized int read(byte b[], int off, int len) {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
}
if (pos >= count) {
return -1;
}
int avail = count - pos;
if (len > avail) {
len = avail;
}
if (len <= 0) {
return 0;
}
System.arraycopy(buf, pos, b, off, len);
pos += len;
return len;
}
public synchronized long skip(long n) {
long k = count - pos;
if (n < k) {
k = n < 0 ? 0 : n;
}
pos += k;
return k;
}
public synchronized int available() {
return count - pos;
}
public boolean markSupported() {
return true;
}
public void mark(int readAheadLimit) {
mark = pos;
}
public synchronized void reset() {
pos = mark;
}
public void close() throws IOException {
}
}
从源码中可以看出,ByteArrayInputStream完全是基于字节数组来实现的,下面我们来详细分析一下。
ByteArrayInputStream中封装了几个属性:
- buf数组用于存储从流中读取的数据
- pos表示下一个即将被读取的字节索引
- mark表示被标记的索引位置,当调用reset方法时,pos的值重置为mark值。mark方法中的参数无实际意义(也许有,但我没看明白T_T)
- count表示字节流的总长度。
下面写一个小例子来说明这些方法的使用:
package ByteArrayIO;
import java.io.ByteArrayInputStream;
public class ByteArrayIOTest2 {
public static final int LENGTH = 3;
public static final byte[] datas = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A };
public static void main(String[] args) {
System.out.println("源数据为:"+new String(datas, 0, datas.length));
new ByteArrayIOTest2().test();
}
private void test() {
ByteArrayInputStream bais = new ByteArrayInputStream(datas);
int len;
//将数据源中的数据全部读出,并打印,此时pos应该与count想等
while((len = bais.read()) != -1){
System.out.print((char)len);
}
//将pos重置为0
bais.reset();
//将pos向后跳跃5个字节
bais.skip(5);
//将此处做上标记,下次reset时,pos定位在标记处,这里的参数0无实际意义
bais.mark(0);
System.out.println("\r\n"+(char)bais.read());
bais.skip(10);
System.out.println((char)bais.read());
bais.reset();
System.out.println((char)bais.read());
}
}
同样,ByteAarrayInputStream在流关闭时,也不会影响方法的执行,不会抛出异常,并且数据仍然存在。
以上为本篇的全部内容。