代码之家  ›  专栏  ›  技术社区  ›  Freid001

在S3中上载输入流块后无法解压缩gzip文件

  •  0
  • Freid001  · 技术社区  · 6 年前

    我想采用与multipart uploader类似的方式,获取输入流并将gzip部件上载到S3。 但是,我希望将各个文件部分存储在S3中,而不是将这些部分转换为单个文件。

    为此,我创建了以下方法。 但是,当我尝试gzip解压每个部分时,gzip抛出一个错误并说: gzip: file_part_2.log.gz: not in gzip format .

    我不确定是否正确压缩了每个部分?

    如果我重新初始化gzip输出流: gzip = new GZIPOutputStream(baos); 并设置 gzip.finish() 重新设置字节数组输出流之后 baos.reset(); 然后我可以对每个部分进行解压缩。不知道我为什么要这样做,有没有类似的 reset 对于gzip输出流?

    public void upload(String bucket, String key, InputStream is, int partSize) throws Exception
    {
        String row;
        BufferedReader br = new BufferedReader(new InputStreamReader(is, ENCODING));
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream gzip = new GZIPOutputStream(baos);
    
        int partCounter = 0;
        int lineCounter = 0;
        while ((row = br.readLine()) != null) {
            if (baos.size() >= partSize) {
                partCounter = this.uploadChunk(bucket, key, baos, partCounter);
    
                baos.reset();
            }else if(!row.equals("")){
                row += '\n';
                gzip.write(row.getBytes(ENCODING));
                lineCounter++;
            }
        }
    
        gzip.finish();
        br.close();
        baos.close();
    
        if(lineCounter == 0){
            throw new Exception("Aborting upload, file contents is empty!");
        }
    
        //Final chunk
        if (baos.size() > 0) {
            this.uploadChunk(bucket, key, baos, partCounter);
        }
    }
    
    private int uploadChunk(String bucket, String key, ByteArrayOutputStream baos, int partCounter)
    {
        ObjectMetadata metaData = new ObjectMetadata();
        metaData.setContentLength(baos.size());
    
        String[] path = key.split("/");
        String[] filename = path[path.length-1].split("\\.");
    
        filename[0] = filename[0]+"_part_"+partCounter;
    
        path[path.length-1] = String.join(".", filename);
    
        amazonS3.putObject(
                bucket,
                String.join("/", path),
                new ByteArrayInputStream(baos.toByteArray()),
                metaData
        );
    
        log.info("Upload chunk {}, size: {}", partCounter, baos.size());
    
        return partCounter+1;
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   guest    6 年前

    问题是你用的是单曲 GZipOutputStream 对于所有块。所以您实际上是在编写gzip文件的片段,需要重新组合才能发挥作用。

    对现有代码进行最小更改:

    if (baos.size() >= partSize) {
        gzip.close(); 
        partCounter = this.uploadChunk(bucket, key, baos, partCounter);
        baos = baos = new ByteArrayOutputStream();
        gzip = new GZIPOutputStream(baos);
    }
    

    您需要在循环结束时执行相同的操作。另外,如果行计数器为0,则不应该抛出异常:完全有可能将文件精确地划分为一组块。

    为了改进代码,我将包装 GZIPOutputStream 在一个 OutputStreamWriter 和A BufferedWriter ,这样就不需要显式地进行字符串字节转换。

    最后,不要使用 ByteArrayOutputStream.reset() . 它不会在创建新流的过程中为您节省任何东西,如果您忘记重置,它会为错误打开大门。