Получает несжатый размер этого GZIPInputStream? - PullRequest
11 голосов
/ 06 сентября 2011

У меня есть GZIPInputStream, который я построил из другого ByteArrayInputStream.Я хочу знать исходную (несжатую) длину данных gzip.Хотя я могу прочитать до конца GZIPInputStream, а затем посчитать число, это будет стоить много времени и тратить процессор.Я хотел бы узнать размер, прежде чем читать его.

Есть ли похожий метод, например ZipEntry.getSize() для GZIPInputStream:

public long getSize ()
С: Уровень API 1
Получает несжатый размер этого ZipEntry.

Ответы [ 8 ]

8 голосов
/ 23 сентября 2011

Размер несжатого файла можно определить, прочитав последние четыре байта файла gzipped.

Я нашел это решение здесь:

http://www.abeel.be/content/determine-uncompressed-size-gzip-file

Также по этой ссылке приведен пример кода (исправлено использование long вместо int, чтобы справиться с размерами от 2 ГБ до 4 ГБ, что обернет int):

RandomAccessFile raf = new RandomAccessFile(file, "r");
raf.seek(raf.length() - 4);
byte b4 = raf.read();
byte b3 = raf.read();
byte b2 = raf.read();
byte b1 = raf.read();
long val = ((long)b1 << 24) | ((long)b2 << 16) | ((long)b3 << 8) | (long)b4;
raf.close();

val - длина в байтах. Осторожно: вы не можете определить правильный размер несжатого файла, когда размер несжатого файла был больше 4 ГБ!

4 голосов
/ 02 октября 2012

На основании @ ответа Александра:

RandomAccessFile raf = new RandomAccessFile(inputFilePath + ".gz", "r");
raf.seek(raf.length() - 4);
byte[] bytes = new byte[4];
raf.read(bytes);
fileSize = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt();
if (fileSize < 0)
  fileSize += (1L << 32);
raf.close();
2 голосов
/ 29 октября 2012

Если вы можете угадать степень сжатия (разумное ожидание, если данные похожи на другие данные, которые вы уже обработали), то вы можете определить размер произвольно больших файлов (с некоторой ошибкой). Опять же, это предполагает файл, содержащий один поток gzip. Ниже предполагается, что первый размер, превышающий 90% расчетного размера (на основе расчетного отношения), является истинным размером:

estCompRatio = 6.1;
RandomAccessFile raf = new RandomAccessFile(inputFilePath + ".gz", "r");
compLength = raf.length();
byte[] bytes = new byte[4];
raf.read(bytes);
uncLength = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt();
raf.seek(compLength - 4);
uncLength = raf.readInt();
while(uncLength < (compLength * estCompRatio * 0.9)){
  uncLength += (1L << 32);
}

[установка estCompRatio в 0 эквивалентна @ ответу Александра]

2 голосов
/ 02 октября 2012

Нет надежного способа получить длину, кроме распаковки всей вещи. См. Размер несжатого файла с использованием функции доступа к файлам gzip в zlib .

2 голосов
/ 06 сентября 2011

Есть ли похожий метод, например ZipEntry.getSize () для GZIPInputStream

Нет. Его нет в Javadoc => его нет.

Для чего вам нужна длина ?

0 голосов
/ 18 февраля 2019

Вместо этого получите FileChannel из базового FileInputStream.Он сообщает вам как размер файла, так и текущую позицию сжатого файла.Пример:

@Override
public void produce(final DataConsumer consumer, final boolean skipData) throws IOException {
    try (FileInputStream fis = new FileInputStream(tarFile)) {
        FileChannel channel = fis.getChannel();
        final Eta<Long> eta = new Eta<>(channel.size());
        try (InputStream is = tarFile.getName().toLowerCase().endsWith("gz")
            ? new GZIPInputStream(fis) : fis) {
            try (TarArchiveInputStream tais = (TarArchiveInputStream) new ArchiveStreamFactory()
                .createArchiveInputStream("tar", new BufferedInputStream(is))) {

                TarArchiveEntry tae;
                boolean done = false;
                while (!done && (tae = tais.getNextTarEntry()) != null) {
                    if (tae.getName().startsWith("docs/") && tae.getName().endsWith(".html")) {
                        String data = null;
                        if (!skipData) {
                            data = new String(tais.readNBytes((int) tae.getSize()), StandardCharsets.UTF_8);
                        }
                        done = !consumer.consume(data);
                    }

                    String progress = eta.toStringPeriodical(channel.position());
                    if (progress != null) {
                        System.out.println(progress);
                    }
                }
                System.out.println("tar bytes read: " + tais.getBytesRead());
            } catch (ArchiveException ex) {
                throw new IOException(ex);
            }
        }
    }
}
0 голосов
/ 06 апреля 2018

Более компактная версия вычисления на основе 4 концевых байтов (избегает использования байтового буфера, вызывает Integer.reverseBytes, чтобы изменить порядок следования байтов в байтах)

private static long getUncompressedSize(Path inputPath) throws IOException
{
    long size = -1;
    try (RandomAccessFile fp = new RandomAccessFile(inputPath.toFile(), "r")) {        
        fp.seek(fp.length() - Integer.BYTES);
        int n = fp.readInt();
        size = Integer.toUnsignedLong(Integer.reverseBytes(n));
    }
    return size;
}
0 голосов
/ 06 сентября 2011

Нет, к сожалению, если вы хотите получить несжатый размер, вам придется прочитать весь поток и увеличить счетчик, как вы указали в своем вопросе.Зачем вам нужно знать размер?Может ли оценка размера работать для ваших целей?

...