學習筆記之java.io包中的位元組流(上)—— 基本的InputStream和OutputStream
先看下類的宣告:
1 2 |
public
abstract
class
InputStream implements
Closeable
public
abstract
class
OutputStream implements
Closeable, Flushable
|
可見此二者都是抽象類,而非介面。也就是說除了分別滿足java.io.Closeable和java.io.Flushable,提供了close()和flush()方法的預設實現外,還給出了其它實現,像InputStream就提供了skip()方法實現等。
我們更關心的是InputStream中的幾個read()方法和OutputStream的幾個write()方法。而實際上最核心的read()和write()方法,InputStream和OutputStream並未給出直接實現,這正是InputStream和OutputStream抽象的地方,我們來看下。
InputStream的read()方法:
- public abstract int read() throws IOException; 核心read()方法,留給子類實現。
- public int read(byte b[])
- public int read(byte b[], int off, int len)
後兩者是呼叫第一個方法讀特定長度的資料放入byte陣列中。
OutputStream的write()方法:
- public abstract void write(int b) throws IOException; 核心write()方法,留給子類實現。
- public void write(byte b[])
- public void write(byte b[], int off, int len)
和read()類似,把位元組陣列中的特定資料挨個呼叫第一個write()方法寫出。
再說read()和wirte()實現,那麼就要看一下InputStream和OutputStream的子類。我們先來看看InputStream和OutputStream的直接子類。
在java.io中InputStream的直接子類有:
- java.io.ByteArrayInputStream
- java.io.FileInputStream
- java.io.FilterInputStream
- java.io.ObjectInputStream
- java.io.PipedInputStream
- java.io.SequenceInputStream
- java.io.StringBufferInputStream
而java.io中OutputStream的直接子類有:
- java.io.ByteArrayOutputStream
- java.io.FileOutputStream
- java.io.FilterOutputStream
- java.io.ObjectOutputStream
- java.io.PipedOutputStream
這些當中,FileInputStream和FileOutputStream是與外部IO直接有關係的,而FilterInputStream和FilterOutputStream是“裝飾者”設計實現的基類,其它各類都是特定場景下InputStream和OutputStream的實現,我們來具體看看。
1. FileInputStream/FileOutputStream
顧名思義,是檔案的輸入流和輸出流。檔案存在於哪裡呢?通常存在於外部裝置上,這個是這些實現類中比較特殊的。我們如果做過C語言開發,知道我們通常會open作業系統中的檔案,並保留其檔案描述符fd。其實,在Java中我們也有類似的東西。首先,就有fd屬性,它是FileDescriptor類,和C等底層語言中一樣,這實際上是對底層檔案的一個描述符,和底層檔案進行互動的時候少不了它。實際上在FileInputStream/FileOutputStream物件構造方法中,我們初始化了FileDescriptor的fd物件,並呼叫了open()方法。
遺憾的是,像open()、read()、write()、skip()、available()這些FileInputStream/FileOutputStream中的具體操作方法,在(Sun)JDK中都冠以native,即本地實現,這樣做的好處就是上層開發使用者不必關心,統統交由JVM等底層實現進行處理,實現了平臺無關性。
在FileInputStream還有這樣幾個屬性:
- private final FileDescriptor fd;
- private FileChannel channel = null; JDK1.4之後為了支援NIO的Channel操作
- private final Object closeLock = new Object(); 關閉時的併發同步鎖
- private volatile boolean closed = false; 關閉標誌
-
private static final ThreadLocal<Boolean> runningFinalize =
new ThreadLocal<>(); finalize是否執行的標誌
此外,再簡要看下FileInputStream構造方法的一個具體實現:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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();
}
fd
= new
FileDescriptor();
fd.incrementAndGetUseCount();
open(name);
}
|
其它過載要麼是呼叫了這個方法,要麼實質上是一致的。FileOutputStream也是類似,出了open()呼叫的時候有一個append屬性引數,標誌是否為檔案追加。
2. ByteArrayInputStream/ByteArrayOutputStream
名稱也很直接,實際上就是位元組陣列,在構造類物件的時候給出一個byte陣列。對於ByteArrayInputStream來說,這個byte陣列就是讀取的源頭,而ByteArrayOutputStream則是write()的目的地。
此外,構造方法中還可以指定這個byte陣列的有效起點和長度。