Java 7之傳統I/O - ByteArrayInputStream和ByteArrayOutputStream

先來看ByteArrayOutputStream類中write()方法:

 // Writes the specified byte to this byte array output stream.
    public synchronized void write(int b) {
        ensureCapacity(count + 1);
        buf[count] = (byte) b;
        count += 1;
    }
    /**
     * Writes len bytes from the specified byte array
     * starting at offset off to this byte array output stream.
     */
    public synchronized void write(byte b[], int off, int len) {
        if ((off < 0) || (off > b.length) || (len < 0) ||
            ((off + len) - b.length > 0)) {
            throw new IndexOutOfBoundsException();
        }
        ensureCapacity(count + len);
        System.arraycopy(b, off, buf, count, len);
        count += len;
    }
這個類也是通過向數組中定入值來進行數值傳遞的,而字節數組的大小可以在創建ByteArrayOutputStream時通過構造函數指定,默認的大小爲32.如果在調用write()方法時,都會確保字節數組的容量。如果過小,會自動進行擴容操作。這樣就可以把需要的數據寫到字節數組中去了。還可以通過調用writeTo()方法可以寫入到其他輸出流中,源代碼如下:

 /**
     * Writes the complete contents of this byte array output stream to
     * the specified output stream argument, as if by calling the output
     * stream's write method using out.write(buf, 0, count).
     */
    public synchronized void writeTo(OutputStream out) throws IOException {
        out.write(buf, 0, count);
    }

繼續來看ByteArrayInputStream類,這個類可以從字節數組中讀出數據,具體的源代碼如下:

 public synchronized int read() {
        return (pos < count) ? (buf[pos++] & 0xff) : -1;
    }

    public synchronized int read(byte b[], int off, int len) {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        }

        if (pos >= count) {
            return -1;
        }

        int avail = count - pos;
        if (len > avail) {
            len = avail;
        }
        if (len <= 0) {
            return 0;
        }
        System.arraycopy(buf, pos, b, off, len);
        pos += len;
        return len;
    }
同時也提供了其他的一些方法,如可以跳讀字節的skip()方法、查看剩餘有效字節的avaible()方法等等,有興趣的可以自己去看。下面來舉一個具體應用的例子,如下:

byte[] bytes = { 0,2, 3, 4, 5 };
		try (ByteArrayOutputStream out = new ByteArrayOutputStream();
			 ByteArrayInputStream in = new ByteArrayInputStream(bytes);){
			out.write(bytes);
			System.out.println(out.size());//5
			System.out.println(in.read());//解
			in.skip(1);//2
			in.mark(4);
			System.out.println(in.read());//3
			in.reset();// 從索引爲2的地方重新開始讀
			System.out.println(in.read());//3 
			System.out.println(in.read());
			
		} catch (IOException e) {
			e.printStackTrace();
		}

4、StringBufferInputStream

這個類現在已經不提倡使用了,個人覺得是因爲編碼的原因吧。查看這個類後的源代碼,如下:

 public synchronized int read() {
        return (pos < count) ? (buffer.charAt(pos++) & 0xFF) : -1;
    }

     public synchronized int read(byte b[], int off, int len) {
        if (b == null) {
            throw new NullPointerException();
        } else if ((off < 0) || (off > b.length) || (len < 0) ||
                   ((off + len) > b.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        }
        if (pos >= count) {
            return -1;
        }
        if (pos + len > count) {
            len = count - pos;
        }
        if (len <= 0) {
            return 0;
        }
        String  s = buffer;
        int cnt = len;
        while (--cnt >= 0) {
            b[off++] = (byte)s.charAt(pos++);
        }

        return len;
    }

發現,其實這個類是將字符串中的字符轉換爲字節進行讀取的,如果這個字符串的字符全部爲ISO-8859-1編碼所能表示的,那肯定能正常讀取。但是通常Java都是Unicode編碼,兩個字符,所以如果其中出現了Unicode字符的時候,例如中文,讀取就會不準確。如下舉例:

String str = "馬智AB";
		StringBufferInputStream st = new StringBufferInputStream(str);
		byte[] j = new byte[16];
		st.read(j);
		System.out.println(new String(j)); //lzAB
原因可能大家也知道了,兩個read()方法在獲取到這個字符串的字符(s.charAt())後,強制轉換爲byte或與0xff相與,這樣的結果只能導致取到低8位的編碼,而對於兩個字節編碼的漢字來說,肯定會產生錯誤。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章