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

时间:2021-10-25 21:35:13
  • 字节流缓存区
  • 自定义字节流缓存区
  • 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位。