FileInputStream是InputStream的一个子类,是字节输入流,而InputStream是一个java标准库中提供的一个基本的输入流,位于java.io这个包里,需要注意的是,InputStream不是接口,而是一个抽象类,是所有输入流的超类。
下面的代码演示了如何完整的读取一个FileInputStream的所有字节:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class Demo01 {
public static void main(String[] args) {
// 定义
InputStream in = null;
try {
// 创建(实例化)“字节输入流”对象
in = new FileInputStream("D:\\test\\aa.txt");
// 保存每次读取到的字节值
int data = -1;
// 正常读取 : 0-255
// 读取末尾 : -1
while((data = in.read()) != -1) {
System.out.print((char)data);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
in = null;
}
}
}
}
那么一次读取一个字节效率过于慢,在FileInputStream类中提供了read()方法的重载形式:
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
需要先定义一个byte数组作为缓冲区,read会读取尽可能多的字节并填充到byte[]数组,返回读取的字节数。
FileInputStream使用缓冲区一次读取多个字节代码如下:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
public class Demo03 {
public static void main(String[] args) {
try (InputStream in = new FileInputStream("D:\\test\\mkl.jpg")) {
// 批量读取(缓冲)
byte[] buff = new byte[1024];
int len = -1;
while((len = in.read(buff)) != -1) {
System.out.printf("本次读取%d个字节:%s\n",len,Arrays.toString(buff));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedInputStream是带有缓冲区的字节输入流,继承于FileInputStream,本质上是通过一个内部缓冲区数组实现的,默认容量是8192,具体实现采用了装饰器模式,在构造方法中需要传入一个输入流对象,如果没有传入缓冲区容量,则使用默认的容量。从磁盘中一次读取相应容量的字节,存放到内存中的内部缓冲区。
在使用read()方法中读取字节时,FileInputStream是从磁盘中直接读取字节,而BufferedInputStream是从内存中的内部缓冲区读取字节,相比之下,从内存中读取比从磁盘中读取速度快,性能好。
jdk中BufferedInputStream类的部分源代码:
private static int DEFAULT_BUFFER_SIZE = 8192;
protected volatile byte buf[];
public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
public BufferedInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
使用BufferedInputStream读取字节代码如下:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class Demo04 {
public static void main(String[] args) {
// 带有缓冲区的字节输入流
// 缓冲区默认大小为8192
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\test\\mkl.jpg"))) {
// 从内存的buf缓冲区中读取1个字节
// bis.read()
int data = -1;
while((data = bis.read()) != -1) {
System.out.println(data);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}