FileInputStream从文件系统中的文件获取输入字节。哪些文件可用取决于主机环境,FileInputStream用于读取原始字节流,如图像数据。要读取字符流,请考虑使用FileReader。
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
FileInputStream inputStream =
new FileInputStream("D:\\jdk_s_d\\out.txt");
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) != -1){
String str = new String(bytes,0, len);
System.out.println(str);
}
inputStream.close();
}
}
在创建一个FileInputStream文件输入流时,主要做了两件事,一个是new一个FileDescriptor(文件描述符),一个便是调用了open方法。
不过在此之前,还调用了一个方法,在FileInputStream源码的下方,有这样一个静态块。
private static native void initIDs();
static {
initIDs();
}
它的作用是设置类中(也就是FileInputStream)的属性的内存地址偏移量,便于在必要时操作内存给它赋值,而FileInputStream的initIDs方法只设置了fd这一个属性的内存地址偏移量。
源码(1.8)
/**
* @since JDK1.0
*/
public class FileInputStream extends InputStream
{
/* 打开文件的句柄,用来表示开放文件、开放套接字等 */
private final FileDescriptor fd;
/**
* 引用文件的路径
* (如果流是用文件描述符创建的,则为空)
*/
private final String path;
//用于读取、写入、映射和操作文件的通道
private FileChannel channel = null;
//关闭时的同步锁
private final Object closeLock = new Object();
private volatile boolean closed = false;
/**
* 通过打开与实际文件的连接,创建FileInputStream。
* 将创建一个新的FileDescriptor对象来表示此文件连接
* <p>
* 如果有一个安全管理器,会把name作为参数调用它的checkRead方法
* <p>
* 如果命名文件不存在,是一个目录而不是一个常规文件,
* 或者由于其他原因无法打开读取,则抛出FileNotFoundException.
* FileInputStream inputStream =
* new FileInputStream("D:\\jdk_s_d\\out.txt");
*/
public FileInputStream(String name) throws FileNotFoundException {
//调用下面的FileInputStream(File file)
this(name != null ? new File(name) : null);
}
/**
* FileInputStream inputStream =
* new FileInputStream(new File("D:\\jdk_s_d\\out.txt");
*/
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
fd = new FileDescriptor();
//在这个FD上安装一个Closeable进行跟踪。
//需要时将父引用添加到其他父引用,以简化closeAll
fd.attach(this);
path = name;
open(name);
}
/**
* 使用FileDescriptor创建FileInputStream
* <p>
*/
public FileInputStream(FileDescriptor fdObj) {
SecurityManager security = System.getSecurityManager();
if (fdObj == null) {
throw new NullPointerException();
}
if (security != null) {
security.checkRead(fdObj);
}
fd = fdObj;
path = null;
fd.attach(this);
}
/**
* 打开指定文件进行读取
*/
private native void open0(String name) throws FileNotFoundException;
/**
* 打开指定文件进行读取
*/
private void open(String name) throws FileNotFoundException {
open0(name);
}
/**
* 从这个输入流中读取一个字节的数据。
* 如果还没有可用的输入,则此方法将阻塞
* @return 数据的下一个字节,如果到达文件末尾,则为-1.
*/
public int read() throws IOException {
return read0();
}
private native int read0() throws IOException;
/**
* 以字节序列的形式读取子数组.
* @param b 将数据读入b[]中
* @param off 从b[off]开始
* @param len 要读入的长度
*/
private native int readBytes(byte b[], int off, int len)
throws IOException;
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
/**
* 调用readBytes方法
*/
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len);
}
/**
* 跳过n个字节数据
*/
public native long skip(long n) throws IOException;
/**
* 剩余字节数的估计值.
*/
public native int available() throws IOException;
/**
* 关闭流并释放资源.
*/
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
/**
* 返回当前的FileDescriptor
*/
public final FileDescriptor getFD() throws IOException {
if (fd != null) {
return fd;
}
throw new IOException();
}
/**
* 返回当前的FileChannel
*/
public FileChannel getChannel() {
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, path, true, false, this);
}
return channel;
}
}
private static native void initIDs();
private native void close0() throws IOException;
static {
initIDs();
}
/**
* 确保在不在引用该文件输入流时调用该文件输入流的close方法.
*/
protected void finalize() throws IOException {
if ((fd != null) && (fd != FileDescriptor.in)) {
/* 如果fd是共享的,那么FileDescriptor中的
* 引用将确保只在安全的情况下调用finalizer。
* 使用fd的所有引用都变得不可访问。
* 我们可以调用close()
*/
close();
}
}
}
更多精彩内容请关注微信公众号: