Java IO(二)

下面来说一下IO流的常用基类:

.字节流的抽象基类:

        .InputStream

        .OutputStream

.字符流的抽象基类:

        .Reader

        .Writer

需要注意的是:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀的。例如,InputStream的子类---FileInputStream,Reader的子类---FileReader.

字节流

字节流的基本操作与字符流类同但是它不仅可以操作字符,还可以操作其他的媒体文件。在这里,列出了几个比较常见的字节流,如下所示

        .FileInputStream

        .FileOutputStream

        .BufferInputStream

        .BufferOutputStream

字节输入流---FileInputStream

首先介绍一下字节输入流---FileInputStream。以一个例子来进行讲解。例:向一个文本文件读取数据。

这里我使用字节输出流----FileInputStream读取文件的三种方式,下面会详述这三种方式。首先使用第一种方式来读取文件,给出的示例代码如下,以供参考:

package stream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Demo1_FileInputStream {
/***
* @param args
* @throws IOException 
* @throws FileInoutStream
* */
public static void main(String[] args) throws IOException{
//int read():从此字节中读取一个数据字节
FileInputStream  fis=new FileInputStream("yyy.txt");//创建流对象
// int x=fis.read();    //从硬盘上读取一个字节
// System.out.println(x);
int x;
while((x=fis.read())!=-1){//-1是字节结束标志
System.out.println(x);
}
fis.close();  //关流释放资源
}

}

下面借用一下其他博主的原理图,来对其进行讲解:

Java IO(二)

接下来使用第二种方式来读取文件,同样给出示例代码如下(其中加入了对IOException异常的处理),以供参考。

public class Demo2 _FileInputStream{
    private static final int DEFAULT_SIZE = 1024; // 缓冲区大小可以是1024的整数倍。
    public static void main(String[] args) {
        // 演示第二种读取方式,read(byte[]);
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("tempfile\\fos.txt");
            // 创建一个字节数组。
            byte[] buf = new byte[DEFAULT_SIZE];
            int len = 0;
            // 调用read(byte[])方法
            while ((len = fis.read(buf)) != -1) { // len记录的是往字节数组里存储的字节个数。
                System.out.println(new String(buf, 0, len)); // 将字节数组转成字符串,打印并看一下效果。
            }
        } catch (IOException e) {
            // 将异常信息写入到日志文件中以进行记录。
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    // 一般可以throw RuntimeException异常,或者将异常信息写入到日志文件中以进行记录。
                    e.printStackTrace();
                }
            }
        }
    }

}

从以上的代码中,可知在创建缓冲区(一个字节数组)时,缓冲区的大小一般设置为1024的整数倍。同上,借用图片。Java IO(二)

最后,使用第三种方式来读取文件,给出示例代码如下,仅供参考。

public class Demo3_FileInputStream {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("tempfile/fos.txt");
        System.out.println(fis.available()); // 获取与之关联的文件的字节数。
        byte[] buf = new byte[fis.available()]; // 定义一个刚刚好的缓冲区,不用再循环了。不过慎用!!!
        fis.read(buf);
        String s = new String(buf);
        System.out.println(s);
        fis.close();
    }

}

*不建议使用这种方式,因为有可能会有内存溢出异常。

字节输出流----FileOutputStream

我们知道了 如何使用了字节输入流----FileInputStream读取文件,就要考虑如何写入数据。

现在就有这样一个需求:向一个文本文件中写入数据。

这里使用字节输出流---FileOutputStream向一个文本文件中写入数据,示例代码如下所示:

package stream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo2_FileOutputStream {
/**
* @param args
* @throws IOException
* FileOutputStream 在创建对象的时候是如果没有这个文件会帮我创建出来
* 如果有这个文件就会先将文件清空

* **/
public static void main(String[] args) throws IOException{
// Demo();
//追加数据
FileOutputStream fos=new FileOutputStream("aaa.txt",true);//如果想续写就在第二个参数传递true
fos.write(100);
fos.close();
}
private static void Demo() throws FileNotFoundException, IOException {
FileOutputStream fos=new FileOutputStream("aaa.txt");//创建字节流对象,如果没有就自动创建
fos.write(97);//虽然写出的是一个int数,但是到文件上的是一个字节,会自动取出前三个八位
fos.write(98);
fos.close();
}

}

IO流的标准处理异常代码:

(1)1.6及其以前版本的流的标准处理异常代码方法,这里 不做多余赘述,直接上代码,示例代码如下:

package stream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Try_Finally {
/**
 * @param args
 * @throws IOException 
 * 
 * **/
public static void main(String[] args) throws IOException {
            FileInputStream fis=null;
        FileOutputStream fos=null;
        try{
    fis=new FileInputStream("aaa.txt");
    fos=new FileOutputStream("yyy.txt");
    int b;
    while((b=fis.read())!=-1){
    fos.write(b);
    }
        }finally{          //try-finally嵌套使用处理流的异常关闭
    try{
if(fis!=null)
fis.close();
    }finally{
if(fos!=null)
fos.close();
    }
        }

}

1.7版本的流的标准处理异常代码方法,这里 不做多余赘述,直接上代码,示例代码如下:

package stream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Try_Finally {
/**
 * @param args
 * @throws IOException 
 * 
 * **/
public static void main(String[] args) throws IOException {
//1.7版本的标准的异常处理办法
try(
FileInputStream fis=new FileInputStream("aaa.txt");
FileOutputStream fos=new FileOutputStream("yyy.txt");
){
int b;
while((b=fis.read())!=-1){
fos.write(b);
}       
}//代码块中的内容处理完,自动关闭流对象,无需手动关闭。

}

复制文本文件

想要复制一个文本文件,说到底就是一个读取源数据,并将数据写到目的地的过程,因此就需要用到了流,读用到了输入流,写用到了输出流,并且操作的是文本文件,最终就需要用到字节流中操作文件的流对象。解决这个问题有两个方式,下面会一一进行讲述。

首相使用第一种复制方式,即从源数据中读取一个字节,就往目的地写一个字节。示例代码如下:

public class CopyTextTest {
    public static void main(String[] args) throws IOException {
        copyText();
    }
    public static void copyText() throws IOException {
        // 1、创建一个输入流和源数据相关联。
        FileInputStream fis = new FileInputStream("IO流.txt");
        // 2、创建一个输出流,并通过输出流创建一个目的地。
        FileOutputStream fos = new FileOutputStream("tempfile\\io_copy.txt");
        // 3、读一个,写一个。
        int by = 0;
        while ((by = fis.read()) != -1) {
            fos.write(by);
        }
        fos.close();
        fis.close();
    }
}
接着再来看第二种复制方式,同样给出示例代码如下。
public class CopyTextByBufTest {
    public static void main(String[] args) {
        copyTextByBuf();
    }
    public static void copyTextByBuf() {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream("IO流.txt");
            fos = new FileOutputStream("tempfile\\io_buf_copy.txt");
           // 创建一个缓冲区
            byte[] buf = new byte[1024];
            // 定义记录个数的变量
            int len = 0;
            // 循环读写
            while ((len = fis.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }
        } catch (IOException e) {
            // 异常日志。
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    // 异常日志。
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    // 异常日志。
                    e.printStackTrace();
                }
            }
        }
    }

}

相比较第一种方式,这种方式的复制效率会更高,,建议使用第二种

字节流的缓冲区对象
现在有这样一个需求:复制一个图片。其解决思路如下:
用字节读取流对象和图片关联。
用字节写入流对象创建一个图片文件,用于存储获取到的图片数据。
通过循环读写,完成数据的存储。
关闭资源。

通过以上思路,不难写出如下代码,程序代码与复制一个文本文件非常相似。

import java.io.*;
class CopyPic {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        FileInputStream fis = null;
        try {
            fos = new FileOutputStream("c:\\2.jpg");
            fis = new FileInputStream("c:\\1.jpg");
            byte[] buf = new byte[1024];
            int len = 0;
            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("写入关闭失败");
            }
        }
    }

}

下面通过一张 图来解释其原理:Java IO(二)

复制一个图片的需求解决完之后,接下来就要引出字节流的缓冲区对象了,它们分别是BufferedOutputStream和BufferedInputStream,它俩是怎样使用的呢?下面同样以复制一个图片的案例来看看字节流的缓冲区对象到底是如何应用在代码中的。

public class CopyPicByBufferDemo {
    public static void main(String[] args) throws IOException {
        copyPicByBuffer();
    }
    public static void copyPicByBuffer() throws IOException {
        // 演示缓冲区。
        // 1,创建具体的流对象。
        FileInputStream fis = new FileInputStream("tempfile\\1.jpg");
        // 对流进行缓冲。
        BufferedInputStream bufis = new BufferedInputStream(fis);
        FileOutputStream fos = new FileOutputStream("tempfile\\copy_1.jpg");
        BufferedOutputStream bufos = new BufferedOutputStream(fos);
        byte[] buf = new byte[1024];
        int len = 0;
        while ((len = bufis.read(buf)) != -1) { // 缓冲区的读方法,从缓冲区里面读出来的数据
            bufos.write(buf, 0, len); // 缓冲区的写方法,向缓冲区里面写数据。
            bufos.flush(); // 刷新可有可无,因为缓冲区满了之后会自动刷新。
        }
        fos.close();
        fis.close();
    }
}