Java中IO框架——FileInputStream原始碼解析
阿新 • • 發佈:2019-01-24
屬性
// 檔案描述類,處理開啟的檔案
private final FileDescriptor fd;
// 檔案的路徑,如果該流是通過檔案描述類建立的,該屬性則為空
private final String path;
// 用於讀、寫、對映、操作檔案的通道
private FileChannel channel = null;
// 一個關閉鎖,只在close()方法中使用,確保多執行緒同步呼叫,同時和其他同步方法不衝突(因為這個關閉鎖是自己的物件鎖)
private final Object closeLock = new Object();
// 流是否是關閉的,volatile保證多執行緒的可見性
private volatile boolean closed = false;
建構函式
// 檔案路徑建立File物件,並呼叫下邊的過載的建構函式
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
// 根據File物件來構造檔案輸入流
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) {
// 檔案路徑為null,丟擲空指標異常
throw new NullPointerException();
}
if (file.isInvalid()) {
// 如果file物件無效,丟擲未找到檔案異常
throw new FileNotFoundException("Invalid file path");
}
// 建立檔案描述符
fd = new FileDescriptor();
// 在檔案描述符中儲存該物件引用
fd.attach(this);
// 路徑名賦值path
path = name;
// 開啟該路徑進行讀取
open(name);
}
// 呼叫open0(name)本地方法
private void open(String name) throws FileNotFoundException {
open0(name);
}
// 本地方法,開啟指定路徑的檔案進行讀取
private native void open0(String name) throws FileNotFoundException;
// 根據檔案描述符構造輸入流
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);
}
重要方法
read()
// 從輸入流中讀取下一個位元組的資料,呼叫本地方法
// 該方法一直阻塞直到有可用的資料
public int read() throws IOException {
return read0();
}
// 本地方法,讀取下一個位元組的資料
private native int read0() throws IOException;
帶引數read
可以參考 InputStream 的類似的 read 方法
// 讀取b.length數量的位元組,並從位元組陣列b的0下標開始填滿b陣列
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
// 讀取b.length數量的位元組,並從位元組陣列b的off下標位置開始填滿b陣列
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len);
}
// 本地方法
private native int readBytes(byte b[], int off, int len) throws IOException;
其他本地方法
// 本地方法,跳過n個位元組
public native long skip(long n) throws IOException;
// 本地方法,返回可讀的位元組數
public native int available() throws IOException;
close()
public void close() throws IOException {
// 使用物件鎖
synchronized (closeLock) {
// 如果流已經關閉則返回
if (closed) {
return;
}
// 否則將關閉狀態設為true
closed = true;
}
// 操作檔案的通道不為空,也要進行關閉
if (channel != null) {
channel.close();
}
// 檔案描述符相關資源的關閉,並呼叫本地關閉方法關閉流
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
private native void close0() throws IOException;
finalize()
protected void finalize() throws IOException {
if ((fd != null) && (fd != FileDescriptor.in)) {
// 如果fd正在被其他流使用,就不能進行關閉,只有當所有流都不再引用這個檔案描述符才關閉
close();
}
}
其他方法
// 獲取流物件對應的檔案描述符
public final FileDescriptor getFD() throws IOException {
if (fd != null) {
return fd;
}
throw new IOException();
}
// 獲取流物件對應的通道,如果為空就建立一個新的通道
public FileChannel getChannel() {
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, path, true, false, this);
}
return channel;
}
}
private static native void initIDs();
// 這個靜態塊在類載入時呼叫
// 設定類中屬性的記憶體地址偏移量,便於在必要時操作記憶體給它賦值
static {
initIDs();
}