FileInputStream是InputStream的子类,由名称上就可以知道, FileInputStream主要就是从指定的档案中读取资料至目的地。
FileOutputStream是OutputStream的子类,顾名思义,FileInputStream主要就是从来源地写入资料至指定的档案中。
标准输入输出串流物件在程式一开始就会开启,但只有当您建立一个FileInputStream或FileOutputStream的实例时,实际的串流才会开启,而不使用串流时,也必须自行关闭串流,以释放与串流相依的系统资源。
下面这个程式可以复制档案,程式先从来源档案读取资料至一个位元缓冲区中,然后再将位元阵列的资料写入目的档案:
- FileStreamDemo.java
package onlyfun.caterpillar;
import java.io.*;
public class FileStreamDemo {
public static void main(String[] args) {
try {
byte[] buffer = new byte[1024];
FileInputStream fileInputStream =
new FileInputStream(new File(args[0]));
FileOutputStream fileOutputStream =
new FileOutputStream(new File(args[1]));
System.out.println("复制档案:" +
fileInputStream.available() + "位元组");
while(true) { // 从来源档案读取资料至缓冲区
if(fileInputStream.available() < 1024) {
int remain;
while((remain = fileInputStream.read())
!= -1) {
fileOutputStream.write(remain);
}
break;
}
else {
fileInputStream.read(buffer);
// 将阵列资料写入目的档案
fileOutputStream.write(buffer);
}
}
// 关闭串流
fileInputStream.close();
fileOutputStream.close();
System.out.println("复制完成");
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println(
"using: java FileStreamDemo src des");
e.printStackTrace();
}
catch(IOException e) {
e.printStackTrace();
}
}
}
这个程式示范了两个 read() 方法,一个可以读入指定长度的资料至阵列,一个一次可以读入一个位元组,每次读取之后,读取的指标都会往前进,您使用available()方法获得还有多少位元组可以读取;除了使用File来建立FileInputStream、FileOutputStream的实例之外,您也可以直接使用字串指定路径来建立。
不使用串流时,记得使用close()方法自行关闭串流,以释放与串流相依的系统资源。
BufferedInputStream 与 BufferedOutputStream
在介绍 FileInputStream、 FileOutputStream的例子中,您使用了一个阵列来作为资料读入的缓冲区,以档案存取为例的话,您知道磁碟存取的速度是远低于记忆体中的资料存取速度,为了减少对磁碟的存,您一次读入一定长度的资料,如上一个主题范例中的1024位元组,而写入时也是一次写入一定长度的资料,这可以增加资料存取的效率。
BufferedInputStream与BufferedOutputStream可以为InputStream类的物件增加缓冲区功能,使用它们,您无需自行设计缓冲区。
BufferedInputStream的资料成员buf是个位元阵列,预设为2048位元组大小,当读取资料来源时,例如档案, BufferedInputStream会尽量将buf填满,当使用read()方法时,实际上是先读取buf中的资料,而不是直接对资料来源作读取,当buf中的资料不足时,BufferedInputStream才会再从资料来源中提取资料。
BufferedOutputStream的资料成员buf是个位元阵列,预设为512个位元组,当写入资料时,会先将资料存至buf中,当buf已满时才会一次将资料写至目的地,而不是每次写入都对目的地作写入。
将上一个主题的范例作个改写,这次不用自行设定缓冲区并进行判断了,使用BufferedInputStream、 BufferedOutputStream让程式看来简单一些,也比较有效率:
- BufferedStreamDemo.java
package onlyfun.caterpillar;
import java.io.*;
public class BufferedStreamDemo {
public static void main(String[] args) {
try {
byte[] data = new byte[1];
File srcFile = new File(args[0]);
File desFile = new File(args[1]);
BufferedInputStream bufferedInputStream =
new BufferedInputStream(
new FileInputStream(srcFile));
BufferedOutputStream bufferedOutputStream =
new BufferedOutputStream(
new FileOutputStream(desFile));
System.out.println("复制档案:" +
srcFile.length() + "位元组");
while(bufferedInputStream.read(data) != -1) {
bufferedOutputStream.write(data);
}
// 将缓冲区中的资料全部写出
bufferedOutputStream.flush();
// 关闭串流
bufferedInputStream.close();
bufferedOutputStream.close();
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println(
"using: java UseFileStream src des");
e.printStackTrace();
}
catch(IOException e) {
e.printStackTrace();
}
}
}
为了确保缓冲区中的资料一定被写出,建议最后执行flush()将缓冲区中的资料全部写出目的串流中。
BufferedInputStream、BufferedOutputStream并没有改变来源InputStream或目的 OutputStream的行为,读入或写出时的动作还是InputStream、OutputStream负责, BufferedInputStream、BufferedOutputStream只是在这之前动态的为它们加上一些功能(像是缓冲区功能),在这边是以档案存取串流为例,实际上您可以在其它串流物件上加上BufferedInputStream、BufferedOutputStream功能。