二进制IO
目录
InputStream和OutputStream
InputStream和OutputStream是字节流的两个顶层父类,提供了输入流类与输出流类的通用API。如图6-10所示列出了一些实现二进制I/O的类。
图6-10 二进制I/O类
InputStream
InputStream是输入字节数据用的类,所以InputStream类提供了3种重载的read方法。Inputstream类中的常用方法如表6-3所示。
表6-3 Inputstream类常用方法
方法名 说明 public abstract int read( ) 读取一个byte的数据,返回值是高位补0的int类型值。若返回值=-1说明没有读取到任何字节读取工作结束。 public int read(byte b[ ]) 读取b.length个字节的数据放到b数组中。返回值是读取的字节数。该方法实际上是调用下一个方法实现的 public int read(byte b[ ], int off, int len) 从输入流中最多读取len个字节的数据,存放到偏移量为off的b数组中。 public int available( ) 返回输入流中可以读取的字节数。注意若输入阻塞,当前线程将被挂起,如果InputStream对象调用这个方法的话,它只会返回0,这个方法必须由继承InputStream类的子类对象调用才有用, public long skip(long n) 忽略输入流中的n个字节,返回值是实际忽略的字节数, 跳过一些字节来读取 public int close( ) 我们在使用完后,必须对我们打开的流进行关闭.
OutputStream
OutputStream是输出字节数据用的类,它提供了3个write方法来做数据的输出,这个是和InputStream是相对应的。OutputStream常用方法如表6-4所示。
表6-4 Outputstream类常用方法
方法名 说明 public void write(byte b[ ]) 将参数b中的字节写到输出流。 public void write(byte b[ ], int off, int len) 将参数b的从偏移量off开始的len个字节写到输出流。 public abstract void write(int b) 先将int转换为byte类型,把低字节写入到输出流中。 public void flush( ) 将数据缓冲区中数据全部输出,并清空缓冲区。 public void close( ) 关闭输出流并释放与流相关的系统资源。
FileInputStream和FileOutputStream
FileInputStream类和FileOutputStream类用于从/向文件读取/写入字写。他们的方法都是从InputStream类和OutputStream类继承的。
FileInputStream类和FileOutputStream类没有引入新的方法。与FileReader和FileWriter相比,它们以二进制形式写进该文件,不存在编码解码问题,效率更快。
FileInputStream
FileInputStream类构造方法如表6-5所示。
表6-5 FileInputStream类构造方法
方法名 说明 FileInputStream(File file) 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。 FileInputStream(String name) 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。
【注意】如果试图为一个不存在的文件创建FileInputStream对象,将会发生java.io.NotFoundException异常。
FileOutputStream
要构造FileOutputStream对象,使用如表6-6所示的构造方法。
表6-6 FileOutputStream类常用方法
方法名 说明 FileOutputStream(File file) 使用File对象创建文件输出流对象,如果文件打开失败,将抛出异常。 FileOutputStream(String name) 直接使用文件名或路径创建文件输出流对象。 FileOutputStream(File file, boolean append) 使用File对象创建文件输出流对象,并由参数append指定是否追加文件内容,true为追加,false为不追加。 FileOutputStream(String name, boolean append) 直接使用文件名或路径创建文件输出流对象,并由参数append指定是否追加。 如果这个文件不存在,就会创建一个新的文件,如果这个文件已经存在,前两个构造方法会删除文件的当前内容。为了在文件内容基础上追加新数据,需要采用后两种构造方法,并将append设置为true。
输入输出流的操作步骤
- 使用引入语句引入java.io包:import java.io.*;
- 根据不同数据源和输入输出任务,建立字节流或字符流对象;
- 若需要对字节或字符流信息组织加工为数据,在已建字节流或字符流对象上构建数据流对象。
- 用输入输出流对象类的成员方法进行读写操作,需要时,设置读写位置指针。
- 关闭流对象。
基本使用方法
几乎所有的I/O类中的方法都会抛出异常java.io.IOExcepton。因此,必须在方法中声明会抛出java.io.IOExcepton异常,或将代码放到try-catch块中。
public static void main(String[] args) throws IOException { File f = new File("a.txt"); FileOutputStream fop = new FileOutputStream(f); // 构建FileOutputStream对象,文件不存在会自动新建 OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8"); // 构建OutputStreamWriter对象,参数可以指定编码,默认为操作系统默认编码,windows上是gbk writer.append("中文输入"); // 写入到缓冲区 writer.append("\r\n"); //换行 writer.append("English"); // 刷新缓存冲,写入到文件,如果下面已经没有写入的内容了,直接close也会写入 writer.close(); //关闭写入流,同时会把缓冲区内容写入文件,所以上面的注释掉 fop.close(); // 关闭输出流,释放系统资源 FileInputStream fip = new FileInputStream(f); // 构建FileInputStream对象 InputStreamReader reader = new InputStreamReader(fip, "UTF-8"); // 构建InputStreamReader对象,编码与写入相同 StringBuffer sb = new StringBuffer(); while (reader.ready()) { sb.append((char) reader.read()); // 转成char加到StringBuffer对象中 } System.out.println(sb.toString()); reader.close(); // 关闭读取流 fip.close(); // 关闭输入流,释放系统资源 } }
下面程序,使用二进制I/O完成了文件的复制。
public static void main(String[] args) throws IOException { File srcFile = new File("cache/01_cache.txt"); // 源文件对象 File destFile = new File("src/desc.txt"); // 目标文件对象 // 使用源文件对象创建文件输入流对象 FileInputStream fis = new FileInputStream(srcFile); // 使用目标文件对象创建文件输出流对象 FileOutputStream fos = new FileOutputStream(destFile); int hasRead = 0;// 读取字节长度 byte[] buf = new byte[1024]; // 创建字节数组,作为临时缓冲 System.out.println("开始复制文件..."); while ((hasRead = fis.read(buf)) != -1) { // 循环从文件输入流中读取数据 if(hasRead == 1024){//读取长度等于数组长度 fos.write(buf); }else{// 读取长度<数组长度,复制读取内容 fos.write(Arrays.copyOf(buf, hasRead)); } } System.out.println("文件复制成功!"); fis.close(); // 关闭流 fos.close(); }
使用try-with-resource自动关闭资源
在编写IO操作时经常会忘记关闭IO流,JDK7提供了新的try-with-resource语法来自动关闭IO流,语法格式如下:
try(声明和创建资源){ 使用资源来处理文件 }
使用try-with-resource语法,上面的代码可以这样写:
public static void main(String[] args) throws IOException { File srcFile = new File("01.txt"); // 源文件对象 File destFile = new File("02.txt"); // 目标文件对象 // 使用源文件对象创建文件输入流对象 try (FileInputStream fis = new FileInputStream(srcFile); // 使用目标文件对象创建文件输出流对象 FileOutputStream fos = new FileOutputStream(destFile)) { int hasRead = 0;// 读取字节长度 byte[] buf = new byte[1024]; // 创建字节数组,作为临时缓冲 System.out.println("开始复制文件..."); while ((hasRead = fis.read(buf)) != -1) { // 循环从文件输入流中读取数据 if(hasRead == 1024){//读取长度等于数组长度 fos.write(buf); }else{// 读取长度<数组长度,复制读取内容 fos.write(Arrays.copyOf(buf, hasRead)); } } System.out.println("文件复制成功!"); } }
【注意】当流不需要使用时,记得使用close()方法将其关闭,或者使用try-with-resource语句自动关闭。不关闭流可能会在输出文件中造成数据受损,或导致其他的程序设计错误。
BufferedInputStream和BufferedOutputStream
BufferedInputStream和 BufferedOutputStream类可以通过减少磁盘读写次数来提高输入和输出的速度。
BufferedInputStream:当向缓冲流写入数据时候,数据先写到缓冲区,待缓冲区写满后,系统一次性将数据发送给输出设备,如图6-11所示。
图6-11 BufferedInputStream
若要创建一个BufferedOutputStream流对象,首先需要一个FileOutputStream流对象,然后基于这个流对象创建缓冲流对象。
BufferedOutputStream 类的构造方法如下:
BufferedOutputStream(OutputStream out) BufferedOutputStream(OutputStream out, int size)
下面程序,使用BufferedOutputStream把内容写入到文件buffer.txt中。
public static void main(String[] args) throws IOException { try (FileOutputStream fos = new FileOutputStream("buffer.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos)) { String str = "hello world"; bos.write(str.getBytes()); } }
BufferedOutputStream:当向缓冲流读取数据时候,系统先从缓冲区读出数据,待缓冲区为空时,系统再从输入设备读取数据到缓冲区,如图6-12所示。
若要创建一个BufferedInputStream流对象,需要一个FileInputStream流对象,然后基于这个流对象创建缓冲流对象。BufferedInputStream类的构造方法如下:
- BufferedInputStream(InputStream in)
- BufferedInputStream(InputStream in, int size)
下面程序,使用BufferedInputStream把读取并打印文件buffer.txt中内容。
public static void main(String[] args) throws IOException { try(FileInputStream fis=new FileInputStream("buffer.txt"); BufferedInputStream bis=new BufferedInputStream(fis)){ byte[] bytes=new byte[1024]; int hasRead=0; while((hasRead=bis.read(bytes))!=-1) { System.out.println(new String(bytes,0,hasRead)); } } }
返回 Java程序设计