黑马程序员技术交流社区
标题:
字节流缓冲区的内部原理剖析
[打印本页]
作者:
一步一脚印
时间:
2013-11-15 03:03
标题:
字节流缓冲区的内部原理剖析
22.jpg
(9.98 KB, 下载次数: 28)
下载附件
2013-11-15 02:43 上传
图片上显示的是InputStream基类中的read()方法的api说明,不知道大家有没有发现,read()方法的返回类型是int.
而InputStream是字节输入流对象,也就是它的子类读取文件是一个字节一个字节的读。
那就出现了一个问题,为什么read()方法不返回byte类型而要返回int类型呢?
看一段我们自己自定义的read()方法。
public int myRead() throws IOException{
if(count == 0){
count = in.read(buf);
if(count<0)
return -1;//即输入流读取完数据返回值为-1
pos = 0;
byte b =buf[pos];
count--;//每次读取是一个字节一个字节的读,读一次--一次
pos++;
return b;
}else if(count>0){
byte b =buf[pos];
count--;//每次读取是一个字节一个字节的读,读一次--一次
pos++;
return b;
}
return -1;
}
复制代码
我们读取文件的代码
while((len=fis.read())!=-1){
//进行写操作
}
复制代码
可以看出,当我们读取到-1的时候,终止程序。
问题就是出在这里,字节流的读取是按一个个字节读取的
拿mp3举例,mp3的文件是有很多的2进制数组成。比如
11111111111111101010010100101001010000000000011111111111................
这样的数字组成。那么是不是存在一种情况,当读取的第一个字节就为-1。
我们分析一下,
0000 0001 是1 , -1的二进制是1的二进制取反+1即
1111 1110 +1
------------
1111 1111
所以当出现前8位2进制全为1时, 字节流读取的值就为-1,将会终止写入文件。这就是一种非正常的行为。
为了避免-1这种情况和读取文件结束的-1冲突。
为什么myRead()返回值为int,就是为了保证转型时byte的高位补0,而不是补1.同时不改变原来的值
分析一下
byte:-1 (8)位 ----> int : -1; (32)位
11111111 11111111 11111111 11111111 11111111
例如,将字节 11111111 -->提升了一个int类型, 是-1的原因是因为在8个1面前补的是1导致的,
那么我只要在前面补0,即可以保留原字节数据不变,又可以避免-1的出现。
那么怎么补0呢?
可以采用
11111111 11111111 11111111 11111111
00000000 00000000 00000000 11111111
----------------------------------- &
00000000 00000000 00000000 11111111
就满足了需要的条件
所以将代码改进之后为
public int myRead() throws IOException{
if(count == 0){
count = in.read(buf);
if(count<0)
return -1;//即输入流读取完数据返回值为-1
pos = 0;
byte b =buf[pos];
count--;//每次读取是一个字节一个字节的读,读一次--一次
pos++;
return <font color="#ff0000">b&255;</font>//这里改进,解决了2次读取时出现2进制为-1的情况。
}else if(count>0){
byte b =buf[pos];
count--;//每次读取是一个字节一个字节的读,读一次--一次
pos++;
return <font color="#ff0000">b&0xff</font>;//0xff == 255 == 1111 1111
}
return -1;
}
复制代码
区别就在于代码中的红色代码。
那读取字节-1的问题解决了,又带来了另外一个问题。
当我们read()一次一个字节,返回值为int ,即我们将返回值提升了4个字节,那么我们输出的时候文件大小是否会比源文件大4倍?
可是我们发现复制的时候,文件大小并没有发生变化。
其实read()进行了一次转型。
同时write()的方法内部实行了一个类型强转的操作。例如前面的00000000 00000000 00000000 11111111
执行write()方法时它只获取指定的数据,前面的24位0将不会写入!所以保证了字节流复制文件的正确性。
这个例子虽然很小,但是所蕴含的知识非常细。学到了很多。
希望大家能从中受益!
作者:
wjj410830911
时间:
2013-11-15 03:11
高端大气牛B拽
虽然不是很明白 不过好厉害的样子
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2