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();
    }

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