Java 使用try-with-resource語法關閉GZIPOutputStream,返回Byte[]二進制數據不正確問題

Java 使用try-with-resource語法關閉GZIPOutputStream,返回Byte[]二進制數據不正確問題


try-with-resource語法

try(xxxStream is=new xxxxStream()){
    return is.xxx;
}

try-with語法實際上就是 try-finally對於流處理的一個語法糖,會在try的代碼塊執行完畢後自動添加Finally方法塊,並調用流的Close方法。這麼看來使用try-with-resources來處理gzip流並沒有問題。

使用try-with 處理gzip流

問題
gzip會在close方法中調用finish方法把結果輸出。

 try (ByteArrayOutputStream out = new ByteArrayOutputStream();
        GZIPOutputStream gzip = new GZIPOutputStream(out)) {
        gzip.write(str.getBytes(encoding));
        return out.toByteArray();
    }

使用上面寫法,其實等同於下面的寫法

try {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    GZIPOutputStream gzip = new GZIPOutputStream(out);
    gzip.write(str.getBytes(encoding));
    return out.toByteArray();
}finally{
    gzip.close();
    out.close();
}

就會發生下面錯誤

with code GZIP_UNCOMPRESS_EXCEPTION exception. null 
--->java.io.EOFException: Unexpected end of ZLIB input stream

原因

    return out.toByteArray();


    // java.io.ByteArrayOutputStream.java
    public synchronized byte toByteArray()[] {
        return Arrays.copyOf(buf, count);
    }

發生的原因發生在 這個地方,try-finally 會在 進入finally方法塊之前將return 結果壓棧,執行完畢後再返回棧內值。toByteArray作爲作爲一個Method就會在進入finally塊之前被調用,這樣子就會把結果壓棧。等到finally執行完畢後再返回結果,這裏返回的是引用值,如果是返回數組的引用其實這裏也沒有問題。關鍵是在toByteArray的時候copy了一下,這樣子返回就是一個新的數組引用。導致返回結果的值不對。

結果覆盤

    /**
    * 0 null null null 4 null null null null null 
    * 0 null null null null null null null null null 
    *
    **/
    static class FinallyTestClass implements Closeable {

        public String[] values = new String[10];

        public void setValue(int i, String v) {
            values[i] = v;
        }

        public String[] getValues() {
            String[] vs = new String[10];
            System.arraycopy(values, 0, vs, 0, 10);
            return vs;
        }

        @Override
        public void close() throws IOException {
            values[4] = "4";
            for (String v : values) {
                System.out.print(v + " ");
            }
            System.out.println();
        }
    }

    public String[] tryFinallyTest() throws IOException {
        try (FinallyTestClass f = new FinallyTestClass()) {
            f.setValue(0, "0");
            return f.getValues();
        }
    }

    @Test
    public void finallyTest() throws IOException {
        String[] vs = tryFinallyTest();
        for (String v : vs) {
            System.out.print(v + " ");
        }
        System.out.println();
    }

    /**
    * 0 null null null 4 null null null null null 
    * 0 null null null 4 null null null null null 
    *
    **/
    static class FinallyTestClass implements Closeable {

        public String[] values = new String[10];

        public void setValue(int i, String v) {
            values[i] = v;
        }

        public String[] getValues() {
           return values;
        }

        @Override
        public void close() throws IOException {
            values[4] = "4";
            for (String v : values) {
                System.out.print(v + " ");
            }
            System.out.println();
        }
    }

    public String[] tryFinallyTest() throws IOException {
        try (FinallyTestClass f = new FinallyTestClass()) {
            f.setValue(0, "0");
            return f.getValues();
        }
    }

    @Test
    public void finallyTest() throws IOException {
        String[] vs = tryFinallyTest();
        for (String v : vs) {
            System.out.print(v + " ");
        }
        System.out.println();
    }

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