Java基础知识IO流(字节流的缓存区并自定义)

  • 字节流缓存区
  • 自定义字节流缓存区
  • read()和write()方法的特点

字节流缓存区

字节流也有缓存区
BufferedInputStream
BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。
BufferedOutputStream
该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。

缓存原理
以将MP3文件复制到别处为例:

BufferedInputStream bufis=new BufferedInputStream(new FileInputStream("music.mp3"));
bufis.read();

MP3文件存放在硬盘上,文件内都是字节数据。当bufis.read();时,不是直接在硬盘上读取字节数据,而是先用FileInputStream()的read(byte[])方法读取字节缓存到内存的缓冲区(字节数组)中,并返回读取的字节数,定义计数器,初始值就是该字节数,再从缓冲区(字节数组)取出数据,读取数据时定义一个指针,一个一个地读取,每 读取一个,指针指向下一个,同时计数器减1,直到减到0时,说明本组数据读完,再读下一组数据到缓存区中(字节数组),直到取到的数据个数是-1时,说明读取完毕。简言之:缓冲区的思想就是从硬盘上获取一批数据到内存缓冲区中,一个一个读取,然后再获取一批数据一个个读取,这样效率比较高。

自定义字节流缓存区

已知缓存原理,自定义字节流的缓冲区:
1.定义缓冲区
2.定义计数器(初始值是0,myRead()方法中当判断到count=0时,将count数值设置为读取到字节数组中的字节数)
3.定义指针 (初始值是0)
4.自定义myRead()方法,读取一个字节,返回int型数据。
5.自定义myClose()方法。

import java.io.*;

class MyBufIsTest 
{
    public static void main(String[] args) throws IOException
    {
        long start = System.currentTimeMillis();
        copy_2();
        long end = System.currentTimeMillis();
        System.out.println((end-start)+"毫秒");
    }

    public static void copy_2()throws IOException
    {
        MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("testCopyJpg.jpg"));
        BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("testCopyJpg2.jpg"));

        int by = 0;

        //System.out.println("第一个字节:"+bufis.myRead());

        while((by=bufis.myRead())!=-1)
        {
            bufos.write(by);
        }

        bufos.close();
        bufis.myClose();
    }
}


class MyBufferedInputStream
{
    private InputStream is=null;
    private int count=0;
    private int pos=0;
    private byte[] buf=new byte[1024];

    MyBufferedInputStream(InputStream is)
    {
        this.is=is;
    }
    //一次读一个字节,从缓存区(字节数组)获取
    public int myRead()throws IOException
    {
        //通过is对象读取硬盘上的数据,并存储在buf中,即进行缓存。
        //先判断count是否为0,若为零表示初次读取或者数组中的字节已读完,那么读取一批数据到字节数组中。
        //再判断此时count是否小于0,若小于0,表示硬盘上的数据已读完,返回-1
        //然后pos=0,从数组的第一个数据开始读
        //读完后pos++,count--
        //将读取的byte类型的b与0xff进行&运算:之所以没有直接强转int,因为强转时,前面添加1,那么前8位为-1,会误以为读取完毕,与0xff&运算的话,
        //前面添加0,就避免了这种情况。

        //若count大于0,说明数组中的数据还未读完,继续读取数据,并count--,pos++,同样b&0xff
        //若count是否小于0,表示硬盘上的数据已读完,返回-1。

        if(count==0)
        {
            count=is.read(buf);
            if(count<0)
                return -1;
            pos=0;
            byte b=buf[pos];
            pos++;
            count--;
            return b&0xff;
        }
        else if(count>0)
        {
            byte b=buf[pos];
            pos++;
            count--;
            return b&0xff;
        }
        return -1;

    }

    public void myClose() throws IOException
    {
        is.close();
    }


}

read()和write()方法的特点

read()方法的返回值类型是int类型,通过与0xff进行&操作,而不是强转为int类型,是为了在前面添0,即保留了原字节数据不变,又避免了-1的出现。
write(int b)方法会强制将int类型的参数b强转危byte类型,只保留最低8位。

你可能感兴趣的:(Java基础知识IO)