Получает несжатый размер этого GZIPInputStream?

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

есть ли подобный метод, как ZipEntry.getSize() на GZIPInputStream:

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

7 ответов


есть ли аналогичный метод, такой как ZipEntry.getsize не() для GZIPInputStream

нет. Это не в Javadoc => его не существует.

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


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

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

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

также из этой ссылки есть пример кода (исправлено использование long вместо int, справиться с размерами между 2GB и 4GB, которые сделают 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 ГБ!


на основе ответа @Alexander:

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();

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


Если вы можете догадаться о степени сжатия (разумное ожидание, если данные похожи на другие данные, которые вы уже обработали), то вы можете вычислить размер произвольно больших файлов (с некоторой ошибкой). Опять же, это предполагает файл, содержащий один поток 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 эквивалентна @Alexander's ответ]


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


более компактная версия расчета, основанная на 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;
}