Domanda

Ho un GZIPInputStream che ho costruito da un altro ByteArrayInputStream. Voglio sapere la lunghezza originale (non compresso) per i dati gzip. Anche se posso leggere fino alla fine del GZIPInputStream, poi contare il numero, costerà molto tempo e CPU rifiuti. Vorrei conoscere la dimensione prima di leggerlo.

Esiste un metodo simile come ZipEntry.getSize() per GZIPInputStream:

public long getSize ()
Dal: API Livello 1
Ottiene la dimensione non compressa di questo ZipEntry.

È stato utile?

Soluzione

Esiste un metodo simile come ZipEntry.getSize () per GZIPInputStream

No. Non è nel Javadoc => non esiste.

Cosa ti serve la lunghezza per

Altri suggerimenti

E 'possibile determinare la dimensione non compressa leggendo gli ultimi quattro byte del file compresso con gzip.

Ho trovato qui questa soluzione:

http://www.abeel.be/content/determine- non compresso in formato gzip-file

Anche da questo link c'è qualche esempio di codice (corretto uso long anziché int, per far fronte alle dimensioni tra 2GB e 4GB che renderebbe un involucro intorno 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 è la lunghezza in byte. Attenzione: non è possibile determinare la dimensione non compressa corretto, quando il file non compresso è maggiore di 4 GB

In base a @ risposta di 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();

Non v'è alcun modo affidabile per ottenere la lunghezza diversa da decompressione il tutto. Vedere file non compresso utilizzando la funzione di accesso ai file gzip di zlib .

Se si può intuire al rapporto di compressione (un'aspettativa ragionevole se i dati è simile ad altri dati che hai già elaborati), allora si può risolvere la dimensione dei file di grandi dimensioni in modo arbitrario (con qualche errore). Ancora una volta, questo presuppone un file contenente un unico flusso gzip. Di seguito si presuppone la prima dimensione maggiore del 90% della dimensione stimata (basato sul rapporto previsto) è la dimensione reale:

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

[impostazione estCompRatio a 0 equivale a @ risposta di Alexander]

Una versione più compatta del calcolo basato sulla coda 4 byte (evita di utilizzare un buffer di byte, chiamate Integer.reverseBytes per invertire l'ordine dei byte di byte letti).

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;
}

No, purtroppo se si voleva ottenere la dimensione non compressa, si dovrà leggere l'intero flusso e incrementare un contatore, come si menziona nella sua interrogazione. Perché avete bisogno di conoscere le dimensioni? Potrebbe una stima del lavoro di formato per i vostri scopi?

Prendi il FileChannel dal FileInputStream sottostante, invece. Vi dice sia la dimensione del file e la posizione corrente del file compresso. Esempio:

@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);
            }
        }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top