Jre的bug之一:文件處理中的字節數組讀寫ByteOutputStream

在將文件以字節流的方式讀到內存時,發現ByteOutputStream(com.sun.xml.internal.messaging.saaj.util.ByteOutputStream(),存在bug。
/**
	 * 
	 * 功能說明:讀取指定路徑文件爲字節數組
	 * @param classPath
	 * @return byte[]
	 * @time:2016年9月20日下午11:42:58
	 * @author:linghushaoxia
	 * @exception:
	 *
	 */
	public static byte[] readBytes(String filePath){
		//返回結果
		byte[] result = null;
		BufferedInputStream inputStream = null;
		ByteOutputStream outputStream=null;
		try {
			inputStream=new BufferedInputStream(new FileInputStream(filePath));
			outputStream= new ByteOutputStream();
			int bufferSize=1024;
			byte[] buffer=new byte[bufferSize];
			while(inputStream.available()>0){
				//還未讀取的字節個數
				int ava = inputStream.available();
				if(ava<bufferSize){
					bufferSize=ava;
				}
				inputStream.read(buffer, 0, bufferSize);
				outputStream.write(buffer, 0, bufferSize);
			}
			//存在問題
			result = outputStream.getBytes();
			//正確,官方不建議使用
			byte[] byteArray=outputStream.toByteArray();
			//更好一些的解決辦法,使用ByteArrayOutputStream
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			/**
			 * 關閉輸入輸出流
			 */
			if (inputStream!=null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if (outputStream!=null) {
				outputStream.close();
			}
		}
		return result;
	}

使用ByteOutputStream.getBytes()會得到包含空數據的字節流,當然和文件的真實數據就不相符了。

原因在於,ByteOutputStream.getBytes獲取的數據包含擴大容量的初始字節;這裏涉及到兩個關鍵屬性buf和count

buf:ByteOutputStream的字節緩衝區

count:實際字節的個數

ByteOutputStream.getBytes,直接返回buf,而buf包含擴容後得到的默認值字節

ByteOutputStream.toByteArray(),則是新建一個字節數組,只讀取buf的一部分:count個長度,這是正確的。

關鍵代碼如下

ByteOutputStream.getBytes()中涉及到buf的部分:

 /**
     * Ensure that the buffer has at least this much space.
     */
    private void ensureCapacity(int space) {
        int newcount = space + count;
        if (newcount > buf.length) {
            byte[] newbuf = new byte[Math.max(buf.length << 1, newcount)];
            System.arraycopy(buf, 0, newbuf, 0, count);
            buf = newbuf;
        }
    }

    public void write(byte[] b, int off, int len) {
        ensureCapacity(len);
        System.arraycopy(b, off, buf, count, len);
        count += len;
    }

ByteOutputStream.toByteArray()相關部分:

/**
     * Evil buffer reallocation method.
     * Don't use it unless you absolutely have to.
     *
     * @deprecated
     *      because this is evil!
     */
    public byte toByteArray()[] {
        byte[] newbuf = new byte[count];
        System.arraycopy(buf, 0, newbuf, 0, count);
        return newbuf;
    }

造成這個問題的原因,在於數據的不一致性:count所代表的真實數據的長度和分配空間得到的buf數組的長度,不一樣。

可見,分配空間中存在一個必須要注意的問題,那就是維護實際數據長度和實際分配空間的關係。

測試環境:Oracle JDK1.7。

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