相对内存的文件操作字节流

字节流的概念

在计算机中,无论文本、图片、音频还是视频,所有文件都是以二进制(字节)形式存在的。IO流中针对字节的输入输出提供了一系列的流,统称为字节流。字节流是程序中最常用的流,根据数据的传输方向可将其分为字节输入流和字节输出流。在JDK中,提供了两个抽象类InputStream和OutputStream,它们是字节流的顶级父类,所有的字节输入流都继承自InputStream,所有的字节输出流都继承自OutputStream。

InputStream被看成一个输入管道,OutputStream被看成一个输出管道,数据通过InputStream从源设备输入到程序,通过OutputStream从程序输出到目标设备,从而实现数据的传输。IO流中的输入输出都是相对于程序而言的

InputStream的常用方法

public static read()
    从此字节流中读取一个数据字节

public static read(byte[] b)
    从此输入流中将最多b.length个字节的数据读入一个byte数组中

public static read(byte[] b,int off,int len)
    指定byte数组中从偏移量off开始的len个字节读出此文件流    

os.close()
    关闭此文件输出流并释放与此流有关的所有系统资源

OutputStream的常用方法

public void write(int b)
    将指定字节写入此文件输出流

public void write(byte[] b)
    将b.length个字节从指定byte数组写入到文件输出流中去

public void write(byte[] b,int off,int len)
    指定byte数组中从偏移量off开始的len个字节写入此文件输出流        

flush() 
    刷新缓存区并强制写出所有缓冲的输出字节    

os.close()
    关闭此文件输入流并释放与此流有关的所有系统资源

InputStream和OutputStream这两个类虽然提供了一系列的读写数据有关的方法,但是这两个类是抽象类,不能被实例化,因此,针对不同的功能,InputStream和OutputStream提供了两个不同的子类,这些子类形成了一个体系结构

字节流读写文件

由于计算机中的数据基本都保存在硬盘的文件中,因此操作文件中的数据时一种很常见的操作。在操作文件时,最常见的就是从文件中读取数据并将数据写入文件,即文件的读写。针对文件的读写,JDK专门提供了两个类,分别是FileInputStream和FileOutputStream。

FileInputStream是InputStream的子类,它是操作文件的字节输入流,专门用于读取文件中的数据。由于从文件中读取数据时重复性的操作,因此需要通过循环语句来实现数据的持续读取。

接下来通过一个案例来实现字节流对文件数据的读取:

public class Example01 {
    public static void main(String[] args) throws Exception {
        //创镌一个文件字节输入流对象
        FileInputStream in = new FileInputStream("test.txt");
        int b=0;            //定义一个int类型的变量b,记住每次读取的一个字节
        while(true) {
            b=in.read();    //变量b记住读取的一个字节
            if(b==-1) {        //如果读取的字节为-1,跳出while循环
                break;
            }
            System.out.println(b);    //否则将b输出
        }
    }
}

与FileInputStream对应的是FileOutputStream。FileOutputStream是OutputStream的子类,他是操作文件的字节输出流,专门把输入写入文件。

接下来通过一个案例来演示如何将数据写入文件:

public class Example02 {
    public static void main(String[] args) throws IOException {
        FileOutputStream out = new FileOutputStream("example.txt");
        String str="波音飞机";
        byte[] b = str.getBytes();
        for (int i = 0; i < b.length; i++) {
            out.write(b[i]);
        }
        out.close();
    }
}

需要注意的是,如果是通过FileOutputStream向一个已经存在的文件中写入数据,那么该文件中的数据首先会被情况,再写入数据。若希望在已存在的文件内容之后追加新内容,则可使用FileOutputStrem的构造函数FileOutputStream(String file, boolean append)来创建文件输出流对象,并把append参数的值设置为true。

接下来通过一个案例来演示如何将数据追加到文件末尾

public class Example01 {
    public static void main(String[] args) throws Exception {
        //创镌一个文件字节输入流对象
        FileInputStream in = new FileInputStream("test.txt");
        int b=0;            //定义一个int类型的变量b,记住每次读取的一个字节
        while(true) {
            b=in.read();    //变量b记住读取的一个字节
            if(b==-1) {        //如果读取的字节为-1,跳出while循环
                break;
            }
            System.out.println(b);    //否则将b输出
        }
    }
}

由于IO流在进行数据读写操作时会出现异常,为了代码的简洁,在上面的程序中使用了throws关键字将异常抛出。然而一遇到IO异常,IO流的close()方法将无法得到执行,流对象所占用的系统资源将得不到释放,因此,为了保证IO流的close()方法必须执行,通常将关闭流的操作写在finally代码块中

finally{
    try{
        if(in!=null){
            in.close;
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

文件的拷贝

在应用程序中,IO流通常都是成对出现的,即输入流和输出流一起使用。例如文件的拷贝就需要通过输入流来读取文件中的数据,通过文件输出流写入文件。

接下来通过一个案例来演示如何进行文件内容的拷贝:

public class Example01 {
    public static void main(String[] args) throws Exception {
        //创建一个字节输入流,用于读取当前目录下sourse文件夹中的map3文件
        FileInputStream in = new FileInputStream("sourse\\周深 - 大鱼.mp3");
        
        //创建一个字节输出流,用于把读取的字节写入到target目录下的文件中
        FileOutputStream out = new FileOutputStream("target\\周深 - 大鱼.mp3");

        int len;    //定义一个整型类型的变量len,记住每次读取的一个字节
        long starttime = System.currentTimeMillis();         //获取拷贝文件前的系统时间
        while((len=in.read())!=-1) {
            out.write(len);      //将读到的字节写入文件
        }
        long endtime = System.currentTimeMillis();
        System.out.println("拷贝时间: "+(endtime-starttime)+"毫秒");
        in.close();
        out.close();
    }
}

字节流的缓冲区

在拷贝文件时,可以一次性读取多个字节的数据,并保存在字节数组中,然后将字节而数组中的数据一次性写入文件。

接下来通过修改文件来学习如何使用缓冲区拷贝文件

public class Example02 {
    public static void main(String[] args) throws Exception {
        //创建一个文件输入流,用于读取当前目录下sourse目录下的mp3文件
        FileInputStream in = new FileInputStream("sourse\\周深 - 大鱼.mp3");
        
        //创建一个文件输出流,用于将读取的数据写入当前目录下的target文件中
        FileOutputStream out = new FileOutputStream("target\\周深 - 大鱼.mp3");
        
        //以下是用缓冲区读写文件
        byte[] buff = new byte[1024];    //定义一个字节数组,作为缓冲区
        
        int len;
        long startTime = System.currentTimeMillis();
        while((len=in.read(buff))!=-1) {    //判断是否读到文件末尾
            out.write(buff, 0, len);    //从第一个字节开始,想文件写入len个字符
        }
        long endTime = System.currentTimeMillis();
        System.out.println("拷贝文件所用的时间:"+(endTime-startTime));
        in.close();
        out.close();
    }
}

在拷贝过程中,使用while循环逐渐实现字节文件的拷贝,每循环一次,就从文件读取若干字节填充字节数组,并通过变量len记住读入数组的字节数,然后从数组的第一个字节开始,将len个字节一次写入文件。循环往复,当len值为-1时,说明已经读到了文件的末尾,循环会结束,整个拷贝过程也就结束了。
程序中的缓冲区就是一块内存,该内存主要用于存放暂时输入输出的数据,由于使用缓冲区减少了对文件的操作次数,所有可以提高读写数据的效率。

在IO包中提供两个带缓冲的字节流,分别是BufferedInputStream和BufferedOutputStream,它们的构造方法中分别接收InputStream和OutputStream类型的参数作为对象,在读写数据时提供缓冲功能。

接下来通过一个案例来学习BufferedInputStream和BufferedOutputStream这两个流的用法:

public class Example03 {
    public static void main(String[] args) throws Exception {
        //创建一个带缓冲区的输入流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src.txt"));
    
        //创建一个带缓冲区的输出流
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("des.txt"));
        int len;
        while((len=bis.read())!=-1){
            bos.write(len);
        }
        bis.close();
        bos.close();
    }
}

当调用了read()或者write()方法读写数据时,首先将读写的数据存入定义好了的字节数组,然后将字节数组一次性写入到文件中。从而提高了数据的读写效率

 

posted @ 2019-10-13 23:01  tunan96  阅读(331)  评论(0编辑  收藏  举报