本帖最后由 xuemeng 于 2013-5-14 18:37 编辑
我贴上自己的笔记和代码吧 ,其实这个问题老毕有讲过!! 这个涉及到字节输入流的缓冲区读取原理了:
import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; class Demo { public static void main(String[] args) throws IOException { MyBufferedInputStream mbis = new MyBufferedInputStream( new FileInputStream("d:\\a.mp3")); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream("d:\\c.mp3")); int num = 0; while ((num = mbis.myRead()) != -1) { bos.write(num); } bos.close(); mbis.myClose(); } } class MyBufferedInputStream { // 自定义缓冲区, 肯定是一个装饰类, 那么肯定有个InputStream类型的私有属性,一个带InputStream类型参数的构造器 // 因为要到缓冲区去读数据,那么就要定义一个缓冲区,保证能够读取缓冲去的数据, 还要一个指针变量和计数器 // 定义InputStream类型的属性 private InputStream is; // 定义指针属性 private int pos = 0; // 定义计数器,记录从硬盘读取到的字节个数,同时,当用户从缓冲区中读取数据后,相对应的要减去, 以判断缓冲区中是否还有数据 private int count = 0; // 定义一个容器,该容器是is对象从硬盘读取到的数据所存放的缓存区 private byte[] bytes = new byte[1024]; public MyBufferedInputStream(InputStream is) { this.is = is; } // 定义读取数据方法,这个方法实际上是读取is对象读取到缓冲去的数据 public int myRead() throws IOException { // 当调用myRead()方法时, 判断计数器是不是0,如果是0, 那么就要用is对象调用read(byte[] // b)方法到硬盘上去读取数据到硬盘上 if (count == 0) { // is对象读取数据到缓冲区 count = is.read(bytes); // 判断是否读取到数据, 如果count值小于0, 说明硬盘上没有数据可读,那么调用myRead()方法一样什么也读不到,返回-1 if (count < 0) { return -1; } // 如果当count==0成立, 那么is对象就会到硬盘上读取数据存储到缓冲区中, 这个时候,读取到的数据,指针必然指向0下标; // 因为这个时候is对象要先读取数据到缓冲区, 用户从缓冲区读数据,刚独到缓冲去的数据, 那么记录的数据必然从0下标开始 pos = 0; // 如果不是, 那么就表示读取到数据了,那么就把存储到缓冲区bytes中的第一个下标的值返回去 byte b = bytes[pos]; // 为了读取下个数据,指针要指向下一个值,计数器要减1,记录缓冲区还有多少数据没有被读取 pos++; count--; // 把从缓存区读取到的数据返回给用户 return b & 255; // 当调用myRead方法,还有一种可能,就是缓冲区有数据, 如果有数据,这个时候指针和计数器一定 } else if (count > 0) { byte b = bytes[pos]; pos++; count--;
//注意看这里的红色字体部分!!1 // 这里最后为什么返回的b还要做一个 & 运算? 而且为什么本方法返回值是int类型, 而不是byte类型? // 原因是, 假如is对象读取到的数据中有这么一个字节 1111-1111, 这个数据的十进制其实就是 -1, 而我们在使用 // myRead()方法读取数据时, 用-1来判断数据是否读取完, 这样就会出问题了, 因为明明缓冲区中有数据, 只因为我们读取的 // 数据是-1, 返回-1, 导致缓冲区的数据没法继续读取了.这样绝对不可以,所以做一个与运算 // 11111111 (字节b) // 00000000 - 00000000 - 00000000 - 11111111 (int类型的255进行&运算) // 00000000 - 00000000 - 00000000 - 11111111 // (结果原数据没变,但是补0了,那么返回的就是10进制的255了,那么这样不是数据变了吗,其实并非如此,在写的时候,又会把这个数据前面的0截取掉, // 那么最后写入的又是 11111111, 也就是-1; return b & 0xff; } return -1; } // 写自己的关闭资源的方法 public void myClose() throws IOException { is.close(); } }
|