|
在书P560介绍BufferedOutpuStream/BufferedOutputStream这个缓冲输出流/输出流时,文中写道:
“由于字符串“你好啊”的UTF-8的编码超过了缓冲区的容量,BufferedOutputStream会自动把缓冲区的所有数据写道data.txt文件中”,这里书中设定了一个条件就是将缓冲区大小设置为2个字节。那么如果我们写入的字符串的字节数为奇数个子节,那么最终多出来的字节数会不会写入到文件中呢?由于缓冲区固定大小为2,那么剩下的字节数该如何处理呢?
假定缓冲区的大小为size,BufferedOutputStream是一旦缓冲区满,那么就直接将缓冲区中的内容写入到文件或数据汇中,然后继续从字符串的字节数组中取size个字节,然后继续判断,那么最终会剩下1个字节不会写入到文件中。基于上述假设,我将要写入的字符串设定为“abc”,那么字节数为3,最终运行结果发现仍然能够将“abc”所有的内容写入到文件中,而不是“ab”。因此Java并不是按照上述设定来进行缓冲区数据的读写的。
于是我阅读了BufferedOutputStream的源码,其中writeUTF()中调用了BufferedOutput的write方法。这个方法大致如下:
static int writeUTF(String str, DataOutput out) throws IOException {
int strlen = str.length();
int utflen = 0;
int c, count = 0;
/* use charAt instead of copying String to char array */
for (int i = 0; i < strlen; i++) {
c = str.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
utflen++;
} else if (c > 0x07FF) {
utflen += 3;
} else {
utflen += 2;
}
}
if (utflen > 65535)
throw new UTFDataFormatException(
"encoded string too long: " + utflen + " bytes");
//上述代码是统计字符串的字节个数
byte[] bytearr = null;
if (out instanceof DataOutputStream) {
DataOutputStream dos = (DataOutputStream)out;
if(dos.bytearr == null || (dos.bytearr.length < (utflen+2)))
dos.bytearr = new byte[(utflen*2) + 2];
bytearr = dos.bytearr;
} else {
bytearr = new byte[utflen+2];
}
bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
int i=0;
for (i=0; i<strlen; i++) {
c = str.charAt(i);
if (!((c >= 0x0001) && (c <= 0x007F))) break;
bytearr[count++] = (byte) c;
}
//上述代码是将字符串转化为字节数组,然后存放在byrearr中
//中间代码略
out.write(bytearr, 0, utflen+2);
return utflen + 2;
//调用BufferedOutputStream对象的write(byte b[], int off, int len)方法
}
BufferedOutputStream方法为:
public synchronized void write(byte b[], int off, int len) throws IOException {
if (len >= buf.length) {
flushBuffer();
out.write(b, off, len);
return;
}
if (len > buf.length - count) {
flushBuffer();
}
System.arraycopy(b, off, buf, count, len);
count += len;
}
字节数组b为要写入的字符串的字节数组,buf为缓冲区字节数组,从上述代码可以看出,BufferedOutputStream首先会判断所要写入的内容字节数是否大于缓冲区容量size
如果大于缓冲区容量size:
先将缓冲区已有的内容写入到文件或数据汇中
然后将字符串的字节数组直接写入到文件中(不经过缓冲区)
如果小于缓冲区大小:
判断字符串的字节大小加上缓冲区已有的字节长度是否大于缓冲区容量size
如果大于缓冲区容量size
先将缓冲区内容写入到文件中
将字符串字节数组b直接复制到缓冲区数组b中
因此,BufferedOutputStream的写入规则是:
如果写入的字符串的字节数大于缓冲区:
那么首先将缓冲区的内容先写入到文件中,然后直接将该字符串的字节数组b写入到文件中
否则,判断字符串字节数组b的大小加上缓冲区中已存在的字节数之和是否大于缓冲区容量size,如果大于缓冲区容量,就将缓冲区的内容写入到文件中,然后再将字符串字节数组写入到缓冲区数组中,如果小于缓冲区容量size, 那么直接将字符串字节数组复制到缓冲区中。
程序猿的技术大观园:www.javathinker.net
|
|