先来看ByteArrayOutputStream类中write()方法:
// Writes the specified byte to this byte array output stream.
public synchronized void write(int b) {
ensureCapacity(count + 1);
buf[count] = (byte) b;
count += 1;
}
/**
* Writes len bytes from the specified byte array
* starting at offset off to this byte array output stream.
*/
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;
}
这个类也是通过向数组中定入值来进行数值传递的,而字节数组的大小可以在创建ByteArrayOutputStream时通过构造函数指定,默认的大小为32.如果在调用write()方法时,都会确保字节数组的容量。如果过小,会自动进行扩容操作。这样就可以把需要的数据写到字节数组中去了。还可以通过调用writeTo()方法可以写入到其他输出流中,源代码如下:
/**
* Writes the complete contents of this byte array output stream to
* the specified output stream argument, as if by calling the output
* stream's write method using out.write(buf, 0, count).
*/
public synchronized void writeTo(OutputStream out) throws IOException {
out.write(buf, 0, count);
}
继续来看ByteArrayInputStream类,这个类可以从字节数组中读出数据,具体的源代码如下:
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;
}
同时也提供了其他的一些方法,如可以跳读字节的skip()方法、查看剩余有效字节的avaible()方法等等,有兴趣的可以自己去看。下面来举一个具体应用的例子,如下:
byte[] bytes = { 0,2, 3, 4, 5 };
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(bytes);){
out.write(bytes);
System.out.println(out.size());//5
System.out.println(in.read());//解
in.skip(1);//2
in.mark(4);
System.out.println(in.read());//3
in.reset();// 从索引为2的地方重新开始读
System.out.println(in.read());//3
System.out.println(in.read());
} catch (IOException e) {
e.printStackTrace();
}
4、StringBufferInputStream
这个类现在已经不提倡使用了,个人觉得是因为编码的原因吧。查看这个类后的源代码,如下:
public synchronized int read() {
return (pos < count) ? (buffer.charAt(pos++) & 0xFF) : -1;
}
public synchronized int read(byte b[], int off, int len) {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}
if (pos >= count) {
return -1;
}
if (pos + len > count) {
len = count - pos;
}
if (len <= 0) {
return 0;
}
String s = buffer;
int cnt = len;
while (--cnt >= 0) {
b[off++] = (byte)s.charAt(pos++);
}
return len;
}
发现,其实这个类是将字符串中的字符转换为字节进行读取的,如果这个字符串的字符全部为ISO-8859-1编码所能表示的,那肯定能正常读取。但是通常Java都是Unicode编码,两个字符,所以如果其中出现了Unicode字符的时候,例如中文,读取就会不准确。如下举例:
String str = "马智AB";
StringBufferInputStream st = new StringBufferInputStream(str);
byte[] j = new byte[16];
st.read(j);
System.out.println(new String(j)); //lzAB
原因可能大家也知道了,两个read()方法在获取到这个字符串的字符(s.charAt())后,强制转换为byte或与0xff相与,这样的结果只能导致取到低8位的编码,而对于两个字节编码的汉字来说,肯定会产生错误。