尝试通过 RxJava 中的 ZipOutputStream 进行压缩时,Zip 内容已损坏

问题描述 投票:0回答:1

我正在尝试创建一个 zip 文件并通过分段上传路由将该 zip 文件上传到 AWS S3 中。但是,我面临一个问题,文件已成功生成,但文件内的内容已损坏。

这是我尝试取消存档文件时遇到的错误:

Archive:  test2MB.zip
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of test2MB.zip or
        test2MB.zip.zip, and cannot find test2MB.zip.ZIP, period.

这是我为此编写的代码片段

private Single<List<CompletedPart>> zipAndUploadZipParts(String uploadId) {
        List<Single<CompletedPart>> uploadPartObservables = new ArrayList<>();
        final int[] partNumber = {Constants.START_PART_NUMBER};

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream);
        return zipMetadata(zipOutputStream)
                .andThen(uploadZipPart(byteArrayOutputStream, uploadPartObservables, partNumber, uploadId)
                        .onErrorResumeNext(error -> {
                            this.contextRx.log().error(String.format("placeholder", partNumber[0], this.logIdentifier, error.getMessage()), error);
                            return Completable.error(new RuntimeException("Placeholder"));
                        }))
                .andThen(finalizeZipUpload(uploadPartObservables, zipOutputStream, byteArrayOutputStream));
    }
    private Completable zipMetadata(ZipOutputStream zipOutputStream) {
        return Completable.create(emitter -> {
            try {
                ZipEntry metadataEntry = new ZipEntry(Constants.METADATA_FILE_NAME);
                zipOutputStream.putNextEntry(metadataEntry);
                zipOutputStream.write(this.catalogObjectsMetadata.getBytes());
                zipOutputStream.closeEntry();
                emitter.onComplete();
            } catch (IOException exception) {
                this.contextRx.log().error(String.format(Constants.LOG_ERROR_ZIPPING_METADATA, this.logIdentifier, exception.getMessage()), exception);
                emitter.onError(new RuntimeException(String.format(Constants.ERROR_ZIPPING_METADATA)));
            }
        });
    }
    private Completable uploadZipPart(ByteArrayOutputStream byteArrayOutputStream, List<Single<CompletedPart>> uploadPartObservables, int[] partNumber, String uploadId) {
        return Completable.create(emitter -> {
            try {
                byte[] zipData = byteArrayOutputStream.toByteArray();
                uploadPartObservables.add(uploadPart(zipData, partNumber[0]++, uploadId));
                byteArrayOutputStream.reset();
                this.contextRx.log().info(String.format("Uploaded part %d for uploadId %s", partNumber[0] - 1, uploadId));
                emitter.onComplete();
            } catch (Exception exception) {
                emitter.onError(exception);
            }
        });
    }
private Single<List<CompletedPart>> finalizeZipUpload(List<Single<CompletedPart>> uploadPartObservables, ZipOutputStream zipOutputStream, ByteArrayOutputStream byteArrayOutputStream) {
        return Single.defer(() -> {
            try {
                zipOutputStream.finish();
            } catch (IOException e) {
                return Single.error(new RuntimeException("Error finishing zip output stream", e));
            } finally {
                try {
                    zipOutputStream.close();
                } catch (IOException e) {
                    return Single.error(new RuntimeException("Error closing zip output stream", e));
                }
                try {
                    byteArrayOutputStream.close();
                } catch (IOException e) {
                    return Single.error(new RuntimeException("Error closing byte array output stream", e));
                }
            }
            return Single.merge(uploadPartObservables)
                    .toList()
                    .doOnSuccess(parts -> this.contextRx.log().info(String.format(Constants.ALL_PARTS_UPLOADED, this.logIdentifier, parts)))
                    .onErrorReturnItem(new ArrayList<>());
        });
    }

有人可以指导我的代码出了什么问题,导致我的 zip 文件损坏吗?

zip 文件内的内容不应损坏。

java stream zip rx-java zipoutputstream
1个回答
0
投票

您的代码看起来不错,您需要在调用 toByteArray() 函数之前关闭 zipOutputStream 和 byteArrayOutput 流。

在 byte[] zipData = byteArrayOutputStream.toByteArray(); 行之前添加关闭语句

示例代码供参考:

public static void main(String[] args) {
    try {
        String dataToCompress = "this is the test string using ZOS";
        try (OutputStream os = new FileOutputStream("output.zip");
            ByteArrayOutputStream byteStream = new ByteArrayOutputStream(dataToCompress.length());
            ZipOutputStream zipStream = new ZipOutputStream(byteStream)) {
            String filePath = "test.txt";
            File file = new File(filePath);
            ZipEntry zipEntry = new ZipEntry(file.getName());
            zipStream.putNextEntry(zipEntry);
            zipStream.write(dataToCompress.getBytes());
            // Close Statements
            zipStream.close();
            byteStream.close();
            byte[] compressedData = byteStream.toByteArray();
            os.write(compressedData);
        }
        System.out.println("File zipped successfully!");
    } catch (IOException e) {
        e.printStackTrace();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.