Uploaded image for project: 'Commons Compress'
  1. Commons Compress
  2. COMPRESS-686

Compression into BZip2 format has unexpected end of file when using a BufferedOutputStream

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 1.27.0
    • 1.27.1
    • Compressors
    • None

    Description

      Problem

      When a file gets compressed into BZip2 format using class BZip2CompressorOutputStream then the format of the file is not valid.

      This can be proven trying to decompress the compressed file as it will fail with an error. For example using the bzip2 tool raises "bzip2: Compressed file ends unexpectedly;" while this library returns error message "IO Stream is not in the BZip2 format".

      For larger files one can see the last part (block?) of the file doesn't get written to the compressed output. Small files remain empty.

      Reproduction

      The error can be reproduced by running the following Java test on version 1.27.0. This test does not fail against older versions (e.g. 1.26.2).

      java.io.IOException: Stream is not in the BZip2 format
      
      	at org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream.init(BZip2CompressorInputStream.java:545)
      	at org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream.<init>(BZip2CompressorInputStream.java:282)
      	at org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream.<init>(BZip2CompressorInputStream.java:266)
      	at net.ripe.rirstats.service.ArchiveServiceTest.decompressBzip2File(ArchiveServiceTest.java:56)
      	at net.ripe.rirstats.service.ArchiveServiceTest.shouldCompressAndDecompressCorrectly(ArchiveServiceTest.java:30)
      
      import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
      import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
      import org.junit.jupiter.api.Test;
      
      import java.io.BufferedOutputStream;
      import java.io.FileInputStream;
      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.io.InputStream;
      import java.io.OutputStream;
      import java.nio.file.Files;
      import java.nio.file.Path;
      import java.nio.file.Paths;
      import java.nio.file.StandardOpenOption;
      
      import static org.junit.jupiter.api.Assertions.assertEquals;
      
      class ArchiveServiceTest {
      
          @Test
          void shouldCompressAndDecompressCorrectly() throws Exception {
              Path tmpDir = Files.createTempDirectory("compressionTest");
              Path file = Path.of(tmpDir.toString(), "test.txt");
              var contents = "random contents";
              Files.writeString(file, contents, StandardOpenOption.CREATE);
      
              Path compressedFile = compressFile(file);
              Path decompressedFile = decompressBzip2File(compressedFile);
      
              String actual = Files.readString(decompressedFile);
              assertEquals(contents, actual);
          }
      
          private static Path compressFile(Path file) throws IOException {
              Path newFile = Paths.get(file.getParent().toString(), file.getFileName().toString() + ".bz2");
              try (InputStream in = Files.newInputStream(file);
                   BZip2CompressorOutputStream bzOut = new BZip2CompressorOutputStream(
                          new BufferedOutputStream(
                                  Files.newOutputStream(newFile)))) {
      
                  final byte[] buffer = new byte[4096];
                  int n;
                  while ((n = in.read(buffer)) != -1) {
                      bzOut.write(buffer, 0, n);
                  }
              }
              return newFile;
          }
      
          private static Path decompressBzip2File(Path file) throws IOException {
              Path decompressedFile = Paths.get(file.getParent().toString(), file.getFileName().toString() + ".decompressed");
      
              try (InputStream fileInputStream = new FileInputStream(file.toFile());
                   BZip2CompressorInputStream bzIn = new BZip2CompressorInputStream(fileInputStream);
                   OutputStream fileOutputStream = new FileOutputStream(decompressedFile.toFile())) {
      
                  final byte[] buffer = new byte[4096];
                  int n;
                  while ((n = bzIn.read(buffer)) != -1) {
                      fileOutputStream.write(buffer, 0, n);
                  }
              }
              return decompressedFile;
          }
      }
      

      Attachments

        Activity

          People

            ggregory Gary D. Gregory
            richard.blank Richard Blank
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: