通過組織考察,令我突然發覺本身在最經常使用的Java中也有不少不明白的地方,實爲平身一大憾事,今天特地抽時間將這些點滴記錄下來,與你們一塊兒分享java
第一批想整理的知識點以下:算法
閒話很少說,先開始今天的主題,研究一下IO的整個結構vim
從體系結構上劃分,IO系統總共分爲兩大模塊, IO和NIO(非阻塞),IO誕生於JDK1.4以前,JDK1.4時,產生了NIO,而且借用NIO重構了部分IO的代碼,好比FileInputStream中增長了對NIO進行支持的getChannel()方法,再好比Reader和FileReader基本用nio所有重寫了。windows
1、Think in IO數組
IO從實現上,大體分爲字節流和字符流兩種:緩存
FileInputStream is = new FileInputStream("F:\\books\\base\\vim經常使用指令.txt"); byte[] buff = new byte[BUFFER_SIZE]; int readSize = 0; while ((readSize = is.read(buff)) != -1) { System.out.println(readSize); if(readSize<1024){ byte[] tmp = new byte[readSize]; System.arraycopy(buff, 0, tmp, 0, readSize); System.out.print(new String(tmp, "GBK")); }else{ System.out.print(new String(buff, "GBK")); } }
/** * Returns the default charset of this Java virtual machine. * * <p> The default charset is determined during virtual-machine startup and * typically depends upon the locale and charset of the underlying * operating system. * * @return A charset object for the default charset * * @since 1.5 */ public static Charset defaultCharset() { if (defaultCharset == null) { synchronized (Charset.class) { java.security.PrivilegedAction pa = new GetPropertyAction("file.encoding"); String csn = (String)AccessController.doPrivileged(pa); Charset cs = lookup(csn); if (cs != null) defaultCharset = cs; else defaultCharset = forName("UTF-8"); } } return defaultCharset; }
下面詳細敘述一下字節流安全
1、InputStream 和 OutputStream 是兩個 abstact 類,對於字節爲導向的 stream 都擴展這兩個雞肋(基類 ^_^ ) ; app
有兩點注意事項:async
a) 使用PipedInputStream的read方法時候要注意,若是緩衝區沒有數據的話,會阻塞當前線程,在主線程中運行的話,會卡住不動。ide
b)PipedOutputStream所在的線程若是中止,那麼PipedOutputStream所使用的資源也會回收,會形成pipe 的「broken」,PipedInputStream的read方法也會報錯。
「A pipe is said to be broken if a thread that was providing data bytes to the connected piped output stream is no longer alive. 」
FilterInputStream,自己是不能被實例化的,是BufferedInputStream等的父類,其實不建立這個類也能夠實現它的子類,這個類內部的方法幾乎所有都是複用父類的方法。其實它存在的意義更可能是表明一個抽象,意思是在InputStream的基礎之上對返回數據進行了從新包裝或者處理,處理緣由可能各不相同,因而又了各不相同的子類。
LineNumberInputStream,這個類是字節流和字符流轉換中的失敗產物,已經肯定爲被廢棄,廢棄的理由是在字節流中強制的判斷讀取換行,不考慮編碼方面的問題。先無論功能能不能實現,首先從抽象層次上面就有欠缺。挪到字符流裏面就皆大歡喜。對應的有LineNumberReader這個類可使用。具體參見LineNumberReader詳解。
DataInputStream,直接讀取目標文件的byte,拼接或轉化byte爲其餘基本類型,好比下面方法
public final int readInt() throws IOException { int ch1 = in.read(); int ch2 = in.read(); int ch3 = in.read(); int ch4 = in.read(); if ((ch1 | ch2 | ch3 | ch4) < 0) throw new EOFException(); return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); }
public final double readDouble() throws IOException { return Double.longBitsToDouble(readLong()); }
/** * Atomic updater to provide compareAndSet for buf. This is * necessary because closes can be asynchronous. We use nullness * of buf[] as primary indicator that this stream is closed. (The * "in" field is also nulled out on close.) */ private static final AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater = AtomicReferenceFieldUpdater.newUpdater (BufferedInputStream.class, byte[].class, "buf");// 建立原子更新器 ... /** * Fills the buffer with more data, taking into account * shuffling and other tricks for dealing with marks. * Assumes that it is being called by a synchronized method. * This method also assumes that all data has already been read in, * hence pos > count. */ private void fill() throws IOException { byte[] buffer = getBufIfOpen(); if (markpos < 0) pos = 0; /* no mark: throw away the buffer */ else if (pos >= buffer.length) /* no room left in buffer */ if (markpos > 0) { /* can throw away early part of the buffer */ int sz = pos - markpos; System.arraycopy(buffer, markpos, buffer, 0, sz); pos = sz; markpos = 0; } else if (buffer.length >= marklimit) { markpos = -1; /* buffer got too big, invalidate mark */ pos = 0; /* drop buffer contents */ } else { /* grow buffer */ int nsz = pos * 2; if (nsz > marklimit) nsz = marklimit; byte nbuf[] = new byte[nsz]; System.arraycopy(buffer, 0, nbuf, 0, pos); if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {//進行更新比較, 若是buf對象和buffer相同, 那麼進行更新,不一樣的話,不更新 // Can't replace buf if there was an async close. // Note: This would need to be changed if fill() // is ever made accessible to multiple threads. // But for now, the only way CAS can fail is via close. // assert buf == null; throw new IOException("Stream closed"); } buffer = nbuf; } count = pos; int n = getInIfOpen().read(buffer, pos, buffer.length - pos); if (n > 0) count = n + pos; }
public ByteArrayInputStream(byte buf[]) public ByteArrayInputStream(byte buf[], int offset, int length)
public int read() throws IOException { if (in == null) { return -1; } int c = in.read(); if (c == -1) { nextStream();// 讀完一個流之後, 自動變動下一個,可是這個方法不是線程安全的, 兩個一塊兒調,後果十分嚴重 return read(); } return c; } /** * Continues reading in the next stream if an EOF is reached. */ final void nextStream() throws IOException { if (in != null) { in.close(); } if (e.hasMoreElements()) { in = (InputStream) e.nextElement(); if (in == null) throw new NullPointerException(); } else in = null; }
2、OutputStream, 基本每一個InputStream都有一個對應的OutputStream,來實現對應的功能,基本全都是抽象方法。
public FileOutputStream(File file, boolean append) throws FileNotFoundException { String name = (file != null ? file.getPath() : null); SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkWrite(name); } if (name == null) { throw new NullPointerException(); } fd = new FileDescriptor(); fd.incrementAndGetUseCount(); this.append = append; if (append) { openAppend(name); } else { open(name); } }