图片上显示的是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将不会写入!所以保证了字节流复制文件的正确性。
这个例子虽然很小,但是所蕴含的知识非常细。学到了很多。
希望大家能从中受益!
|