Java基础之IO系列(二)

1.本文概述

本文讲解IO系列有关字节流对象部分的内容。

字节流主要包含以下四个部分:

FileOutputStream
FileInputStream

BufferedOutputStream
BufferedinputStream

2.字节流的输出操作

1.输出流OutputStream

常用方法:

void close()
关闭此输出流并释放与此流有关的所有系统资源。
void flush()
刷新此输出流并强制写出所有缓冲的输出字节。
void write(byte[] b)
将 b.length 个字节从指定的 byte 数组写入此输出流。
void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
abstract void write(int b)
将指定的字节写入此输出流。

说明:OutputStream是一个抽象类,无法直接实例化,因此一般使用其直接子类FileOutputStream。

2.文件输出流FileOutputStream

构造方法:

FileOutputStream(File file)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(File file, boolean append)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。如果为append为true,则将字节写入文件末尾处,而不是覆盖整个文件。
FileOutputStream(String name)
创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStream(String name, boolean append)
创建一个向具有指定 name 的文件中写入数据的输出文件流。

常用方法:

void close()
关闭此文件输出流并释放与此流有关的所有系统资源。
void write(byte[] b)
将 b.length 个字节从指定 byte 数组写入此文件输出流中。
void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
void write(int b)
将指定字节写入此文件输出流。
void close()
关闭此输出流并释放与此流有关的所有系统资源。

需求描述:将字符串数据以字节流的形式写入指定文件中

示例代码:

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo {

    public static void main(String[] args) {
        //声明FileOutputStream对象
        FileOutputStream fos=null;
        try {
            //实例化FileOutputStream对象
            fos=new FileOutputStream("G:\\file_out_test.txt");
            //用于输出的目标字符串
            String tarStr="这是通过字节流写入文件的测试数据";
            //以字节流的输出目标字符串
            fos.write(tarStr.getBytes());
            //刷新字节流缓存
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(fos!=null)
                try {
                    //关闭字节流
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }
}

程序运行结果

4.png


3.字节流的读取操作

1.输入流InputSteam

常用方法:

int available()
返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。
void close()
关闭此输入流并释放与该流关联的所有系统资源。
abstract int read()
从输入流中读取数据的下一个字节。
int read(byte[] b)
从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
int read(byte[] b, int off, int len)
将输入流中最多 len 个数据字节读入 byte 数组。

long skip(long n)
跳过和丢弃此输入流中数据的 n 个字节。

说明:FileInputStream是一个抽象类,无法直接实例化,因此一般使用其直接子类FileInputStream。

2.文件输入流FileInputStream

构造方法:

FileInputStream(File file)
通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
FileInputStream(String name)
通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。

常用方法:

int available()
返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。
void close()
关闭此文件输入流并释放与此流有关的所有系统资源。
int read()
从此输入流中读取一个数据字节
int read(byte[] b)
从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
int read(byte[] b, int off, int len)
从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。
long skip(long n)
从输入流中跳过并丢弃 n 个字节的数据。

第一种方式:

    //部分代码
    public static void main(String[] args) {
        //声明FileInputStream对象
        FileInputStream fis=null;
        try {
            //实例化FileInputStream对象
            fis=new FileInputStream("G:\\file_out_test.txt");

            int ch=0;
            while((ch=fis.read())!=-1){
                //将获取到的int型数据强转为char型输出
                System.out.print((char)ch);
            }   

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if(fis!=null)
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

程序运行结果:

test:this file is used by OutputStream

说明:使用这种方式读取数据,目标文件中不能存在中文,否则会出现乱码。因为无参构造方法每次只会读取单个字节,而每个中文由两个字节组成

第二种方式:

    //部分代码
    public static void main(String[] args) {
        //声明FileInputStream对象
        FileInputStream fis=null;
        try {
            //实例化FileInputStream对象
            fis=new FileInputStream("G:\\file_out_test.txt");
            //定义用于临时存储数据的字节数组,请区别于FileReader的字符数组
            byte[] bufArr=new byte[1024];

            //记录读取到的字符数组长度
            int len;
            while((len=fis.read(bufArr))!=-1){
                System.out.println(new String(bufArr,0,len));
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if(fis!=null)
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

程序运行结果:

test:this file is used by OutputStream
test:这里使用了字节数组作为缓冲区
tsst:所以我终于可以出现中文了

第三种方式-特有方式

示例代码:

    //部分代码
    public static void main(String[] args) {
        //声明FileInputStream对象
        FileInputStream fis=null;
        try {   
            //实例化FileInputStream对象
            fis=new FileInputStream("G:\\file_out_test.txt");
            //建立和目标文件字节流大小一致的字节数组
            byte[] bufArr=new byte[fis.available()];
            //读取字节流
            fis.read(bufArr);
            //将字节数组转化为字符串输出
            System.out.println(new String(bufArr));

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if(fis!=null)
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

程序运行结果

test:this file is used by OutputStream
test:这里使用了字节数组作为缓冲区
tsst:所以我终于可以出现中文了

说明:这种方式只适用于文件较小的情况,因为java虚拟机初始化时的默认内存仅为64M

总结:考虑到实际开发中的效率要求,建议使用第二种方式。


4.拷贝图片

需求描述:将G盘根目录下的测试图片复制到D盘

步骤:

1.用字节读取流对象和图片文件关联
2.用字节写入流对象创建一个图片文件,用于存储获取到的图片数据
3.通过循环读写,完成数据存储
4.关闭资源

示例代码:

    //部分代码
    public static void main(String[] args) {
        //声明字节输入输出流对象
        FileOutputStream fos=null;
        FileInputStream fis=null;

        try {
            //进行实例化
            fos=new FileOutputStream("D:\\test.png");
            fis=new FileInputStream("G:\\test.png");

            //临时存储数据的缓冲数组
            byte[] bufArr=new byte[1024];
            //记录读取的数据长度
            int len;
            while((len=fis.read(bufArr))!=-1){
                fos.write(bufArr, 0, len);
                fos.flush();//刷新流缓存
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(fis!=null)
                try {
                    //关闭流
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            if(fos!=null)
                try {
                    //关闭流
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }       
    }

5.字节流的缓冲区

对应类:

BufferedOutputStream
BufferedInputStream

1.缓冲输出流

构造方法:

BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
BufferedOutputStream(OutputStream out, int size)
创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。

常用方法:

void flush()
刷新此缓冲的输出流。
void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流。
void write(int b)
将指定的字节写入此缓冲的输出流。
void close()
关闭此输出流并释放与此流有关的所有系统资源。
void write(byte[] b)
将 b.length 个字节写入此输出流。

2.缓冲输入流

构造方法:

BufferedInputStream(InputStream in)
创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
BufferedInputStream(InputStream in, int size)
创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。

常用方法:

int available()
返回可以从此输入流读取(或跳过)、且不受此输入流接下来的方法调用阻塞的估计字节数。
void close()
关闭此输入流并释放与该流关联的所有系统资源。
int read()
参见 InputStream 的 read 方法的常规协定。
int read(byte[] b)
从此输入流中将 byte.length 个字节的数据读入一个 byte 数组中。
int read(byte[] b, int off, int len)
从此字节输入流中给定偏移量处开始将各字节读取到指定的 byte 数组中。

long skip(long n)
跳过和丢弃此输入流中数据的 n 个字节。

3.简单应用

需求描述:将G盘的MP3文件通过缓冲字节流复制到D盘

示例代码:

    //部分代码
    public static void main(String[] args) {
        long start=System.currentTimeMillis();
        //声明输入输出缓冲字节流对象
        BufferedInputStream bis=null;
        BufferedOutputStream bos=null;

        try {
            //实例化对象
            bis=new BufferedInputStream(new FileInputStream("G:\\test.mp3"));
            bos=new BufferedOutputStream(new FileOutputStream("D:\\test.mp3"));

            //写入数据
            byte[] b=new byte[1024];
            int len=0;
            while((len=bis.read(b))!=-1){
                bos.write(b, 0, len);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if(bos!=null)
                try {
                    //关闭流
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            if(bis!=null)
                try {
                    //关闭流
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            long end=System.currentTimeMillis();
            System.out.println("消耗时间:"+(end-start)+"ms");
        }
    }

程序运行结果

消耗时间:13ms

说明:在本例中可以不使用flush进行刷新。并且因为缓冲流的应用,文件的复制效率得到了大幅度提高

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章