二进制IO

来自CloudWiki
跳转至: 导航搜索


InputStream和OutputStream

InputStream和OutputStream是字节流的两个顶层父类,提供了输入流类与输出流类的通用API。如图6-10所示列出了一些实现二进制I/O的类。

Java6-10.png

图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。

输入输出流的操作步骤

  1. 使用引入语句引入java.io包:import java.io.*;
  2. 根据不同数据源和输入输出任务,建立字节流或字符流对象;
  3. 若需要对字节或字符流信息组织加工为数据,在已建字节流或字符流对象上构建数据流对象。
  4. 用输入输出流对象类的成员方法进行读写操作,需要时,设置读写位置指针。
  5. 关闭流对象。

基本使用方法

几乎所有的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所示。

Java6-11.png

图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所示。

Java6-12.png 图6-12 BufferedOutputStream

若要创建一个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程序设计