Как я могу непрерывно читать из сжатого файла, пока он записывается? - PullRequest
0 голосов
/ 13 октября 2019

Java GZIPInputStream и Apache GzipCompressorInputStream оба отключают себя, как только достигают EOF.

Я хочу иметь возможность распаковывать файл, в который выполняется запись, и когда не хватает данных для распаковки или существуетнет никаких данных, чтобы просто получить -1 и продолжать пытаться читать, пока данные не станут доступны, как с обычным FileInputStream.

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/zip/GZIPInputStream.html https://commons.apache.org/proper/commons-compress/apidocs/org/apache/commons/compress/compressors/gzip/GzipCompressorInputStream.html

ВотОсновной метод, показывающий проблему. Я хотел бы иметь возможность продолжать чтение, как только в файле появятся дополнительные данные. Я сжимаю строки «а» и «б». Я записываю сжатый «а» в файл, затем читаю его. Затем я записываю сжатый «b» в файл, но тот же InputStream никогда не сможет его прочитать, потому что он отключился, когда достиг конца файла после прочтения сжатого «a».

public static void main(String[] args) throws IOException {
    ByteArrayOutputStream firstByteArrayOutputStream = new ByteArrayOutputStream();
    GZIPOutputStream firstGzipOutputStream = new GZIPOutputStream(firstByteArrayOutputStream);
    firstGzipOutputStream.write("a".getBytes(StandardCharsets.UTF_8));
    firstGzipOutputStream.close();
    byte[] firstGzippedBytes = firstByteArrayOutputStream.toByteArray();

    ByteArrayOutputStream secondByteArrayOutputStream = new ByteArrayOutputStream();
    GZIPOutputStream secondGzipOutputStream = new GZIPOutputStream(secondByteArrayOutputStream);
    secondGzipOutputStream.write("b".getBytes(StandardCharsets.UTF_8));
    secondGzipOutputStream.close();
    byte[] secondGzippedBytes = secondByteArrayOutputStream.toByteArray();

    Path combiner = Files.createTempFile("gziptest", "gz");
    FileOutputStream fileWriter = new FileOutputStream(combiner.toFile(), false);
    fileWriter.write(firstGzippedBytes);
    fileWriter.close();

    InputStream b = new GZIPInputStream(new FileInputStream(combiner.toFile()));

    int fromFile = b.read();
    while (fromFile != -1) {
        System.out.print((char) fromFile);
        fromFile = b.read();
    }

    FileOutputStream fileAppender = new FileOutputStream(combiner.toFile(), true);
    fileAppender.write(secondGzippedBytes);
    fileAppender.close();

    fromFile = b.read();

    while (fromFile != -1) {
        System.out.print((char) fromFile);
        fromFile = b.read();
    }
}

Я бы предпочел не реализовывать свой собственный инфлятор ...

Сравните это с последующим использованием простого FileInputStream без сжатия. Все данные считываются - поток начинает возвращать данные после их записи в файл.

public static void main(String[] args) throws IOException {
    ByteArrayOutputStream firstByteArrayOutputStream = new ByteArrayOutputStream();
    firstByteArrayOutputStream.write("a".getBytes(StandardCharsets.UTF_8));
    firstByteArrayOutputStream.close();
    byte[] firstGzippedBytes = firstByteArrayOutputStream.toByteArray();

    ByteArrayOutputStream secondByteArrayOutputStream = new ByteArrayOutputStream();
    secondByteArrayOutputStream.write("b".getBytes(StandardCharsets.UTF_8));
    secondByteArrayOutputStream.close();
    byte[] secondGzippedBytes = secondByteArrayOutputStream.toByteArray();

    Path combiner = Files.createTempFile("gziptest", "gz");
    FileOutputStream fileWriter = new FileOutputStream(combiner.toFile(), false);
    fileWriter.write(firstGzippedBytes);
    fileWriter.close();

    InputStream b = new FileInputStream(combiner.toFile());

    int fromFile = b.read();
    while (fromFile != -1) {
        System.out.print((char) fromFile);
        fromFile = b.read();
    }

    FileOutputStream fileAppender = new FileOutputStream(combiner.toFile(), true);
    fileAppender.write(secondGzippedBytes);
    fileAppender.close();

    fromFile = b.read();

    while (fromFile != -1) {
        System.out.print((char) fromFile);
        fromFile = b.read();
    }
}
...