(85)字节流读写、缓冲区

来源:互联网 发布:阿里云ecs扩容 编辑:程序博客网 时间:2024/06/06 09:51

需求:想要操作图片数据,这就要用到字节流
字节流:InputStream OutputStream(写入)
字符流中用的是字符数组,在字节流中用的是字节数组
将字符串转换为字节数组:public byte[] getBytes()
将字符串转换为字符数组:public char[ ] toCharArray()

import java.io.*;public class FileDemo {    public static void main(String[] args)throws IOException {        //写        FileOutputStream fos=new FileOutputStream("fos.txt");        fos.write("abcde".getBytes());//不用刷新        fos.close();//虽然不刷新,但是得关资源        //读        FileInputStream fis=new FileInputStream("fos.txt");        System.out.println("-----------读的第一种方法----------");        //一个字节一个字节的读:read()方法        /*int num=0;        while ((num=fis.read())!=-1) {            System.out.println((char)num);        }        fis.close();        */        System.out.println("-----------读的第二种方法----------");        //字节数组的读read(byte[] b)        /*byte[] buf=new byte[1024];        int len=0;        while((len=fis.read(buf))!=-1) {            System.out.println(new String(buf,0,len));        }        fis.close();        */        System.out.println("-----------读的第三种方法----------");        // TODO Auto-generated method stub        FileInputStream fis=new FileInputStream("fos.txt");        int len1=fis.available();//返回字节数        System.out.println(len1);        byte[] buf1=new byte[len1];//定义一个刚刚好的缓冲区,因为已经知道长度了,无需循环        fis.read(buf1);        fis.close();        //将所有的数据存入数组        //read(byte[]):从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。         //这个方法完成了两件事情:1:将字符字节流中的数据放入字符数组中2:返回存入的字节长度         System.out.println(new String(buf1));      

对比三种读的方式,第一种循环次数太多,速度太慢;第三种方式,虽然空间正好,因为现在操作的字节流,包括某些电影文件,若电影文件1G,在内存中设置这么大的数组是不合理的,所以一般还是用第二种方式
练习:复制一个图片
1,用字节读取流对象和图片关联
2,用字节写入流对象创建一个图片文件,用于存储获取到的图片数据
3,通过循环读写,完成数据的存储
4,关闭资源
注意:字符流只能用于处理文字数据,不能处理图片数据。
FileInputStream:可以用于读取诸如图像之类的原始字节流

import java.io.*;public class PictureCopy {    public static void main(String[] args) {        // TODO Auto-generated method stub        FileOutputStream fos=null;        FileInputStream fis=null;        try {        fos=new FileOutputStream("picture.png");        fis=new FileInputStream("C:\\picture.png");        int len=0;        byte []buf=new byte[1024];        while((len=fis.read(buf))!=-1) {            fos.write(buf,0,len);          }        }catch(IOException e) {            throw new RuntimeException("复制失败");        }        finally {            try {                if(fis!=null)                    fis.close();            }catch(IOException e) {                throw new RuntimeException("原文件关闭失败");            }            try {                if(fos!=null)                    fos.close();            }catch(IOException e) {                throw new RuntimeException("复制文件关闭失败");            }        }    }}

用缓冲区复制Mp3文件

import java.io.*;public class BufferaMp3Copy {    public static void main(String[] args) {        FileInputStream fis=null;        FileOutputStream fos=null;        BufferedInputStream bis=null;        BufferedOutputStream bos=null;        try{         fis=new FileInputStream("C:\\SBS.mp3");         fos=new FileOutputStream("SBS.mp3");         bis=new BufferedInputStream(fis);         bos=new BufferedOutputStream(fos);         int num=0;         while((num=bis.read())!=-1) {             bos.write(num);             bos.flush();         }        }catch(IOException e) {            throw new RuntimeException("mp3复制失败");        }        finally {            try {                if(bis!=null)                    bis.close();            }catch(IOException e) {                throw new RuntimeException("原关闭失败");            }            try {                if(bos!=null)                    bos.close();            }catch(IOException e) {                throw new RuntimeException("新关闭失败");            }        }    }}

自定义字节流的缓冲区
① 原理图(一次读一个数据(切记)):
这里写图片描述
定义数组:来充当缓冲区
定义指针:用来确定读取数组的哪号元素
定义计数器:用来确定是否要想数组(缓冲区中存入一批数组)

import java.io.*;public class MyBuffer {    private  InputStream  in;    private byte[] buf=new byte[1024];    private int pos=0,count=0;    MyBuffer(InputStream in){        this.in=in;    }    //一次读一个字节(所以没有循环),从缓冲区(字节数组)获取    public int myRead()throws IOException{        //通过in对象读取硬盘上的数据,并存储在buf中        if(count==0) //在count为0,即缓冲区中没数据了,才需要从硬盘上取数据        {        count=in.read(buf);        if(count<0)            return -1;        pos=0;        byte b=buf[pos];//取了每次装入缓冲区的第一个元素        count--;        pos++;        return b&255;        }        else if(count>0)        {            byte b=buf[pos];            count--;            pos++;            return b&255;        }        return -1;    }    public void myClose()throws IOException {        in.close();    }}

mp3数据都是由二进制数据组成的,读一个字节就是读8个二进制位,
11111111-11111000000000011111100000

11111111是-1
【负数的二进制是正数的二进制全取反然后加1。
1的二进制为00000001,取反11111110,加1,11111111】
当读取到11111111(1byte),就返回int(4byte),相当于类型提升。
byte:-1 —–>int:-1
11111111 —>11111111 11111111 11111111 11111111
这样提升完,还是-1,与判断没有数据的条件还是一样,仍然不能继续复制。
就可以补0,而不是补1,就避免了不能复制的情况同时原数据没发生变换(也是返回int类型的原因)
00000000 00000000 00000000 11111111
那么怎样补0呢?(取一个数的最低8位)
11111111 11111111 11111111 11111111
&00000000 00000000 00000000 11111111


00000000 00000000 00000000 11111111
11111111—->提升了一个int类型,还是-1的原因是在8个1的前面补1造成的。
那么只要在前面补0,既可以保留字节数据不变,也可以避免-1的出现。
* 上面的byte–>int类型转换理解后,还有个疑问,就是读出来的是int类型,复制出来的文件应该容量x4,但是从测试结果看出,并没有扩大容量,原因是?*
read类型提升,在write中是类型下降,即在API中写的将指定的字节写入此缓冲的输出流。

原创粉丝点击