A ZIP fájlok végső méretének becslése nehéz feladat, de a végső fájlméretet viszonylag pontosan is meg lehet határozni olyan módon, hogy mintákat veszünk a fájlból és a mintákon elvégezzük a tömörítést, majd a tömörített minták méretéből megbecsüljük a teljes tömörített állomány méretét.

Az általam fejlesztett megvalósításban:

  • ha kisebb a fájl a BUFFER_SIZE mintaméretnél, akkor az egészt fájlt betömörítem a memóriában, így a pontos méretet kapom
  • ha nagyobb a fájlméret a mintánál, akkor ZIP_SAMPLES mennyiségű mintát veszek a fájlból, a mintákat összefűzöm egy egységes tömbbé, a minta tömböt tömörítem össze a memóriában, végül a tömörített tömb méretéből kiszámolom a teljes állomány becsült méretét.

Az így kapott becsült tömörített fájlméret jól közelíti a valódi méretet.

A teljes osztályt innen lehet letölteni:

ZipUtils.java

A következő metódus akár egy több GByte-os fájl méretét is hatékonyan és gyorsan meghatározza:

public static long sizeOfZippedFile(File file) throws FileNotFoundException, IOException {
        long fullLength = Math.min(Integer.MAX_VALUE, file.length());
        int parts = (int) (fullLength / BUFFER_SIZE);
        if (parts <= ZIP_SAMPLES) {
            return exactSizeOfZippedFile(file);
        }
        byte[] sampleArray = new byte[ZIP_SAMPLES * BUFFER_SIZE];
        long ratio = parts / ZIP_SAMPLES;
        int pos = 0;
        int fullPos = 0;
        try (FileInputStream fis = new FileInputStream(file)) {
            while (fullPos < parts) {
                if (fullPos % ratio == 0 && pos < ZIP_SAMPLES) {
                    fis.read(sampleArray, pos * BUFFER_SIZE, BUFFER_SIZE);
                    pos += 1;
                } else {
                    fis.skip(BUFFER_SIZE);
                }
                fullPos += 1;
            }
        }
        return (long) (exactSizeOfZippedByteArray(sampleArray) * (((double) file.length()) / sampleArray.length));
    }

 

Ha a vizsgált fájl mérete elég kicsi, a következő metódusal számoljuk ki a pontos tömörített méretet:

    public static long exactSizeOfZippedFile(File file) throws FileNotFoundException, IOException {
        try (LenghtOutputStream sos = new LenghtOutputStream();) {
            try (ZipOutputStream zos = new ZipOutputStream(sos);) {
                int bytesIn = 0;
                byte[] buffer = new byte[1024];
                try (FileInputStream fis = new FileInputStream(file)) {
                    ZipEntry anEntry = new ZipEntry(file.getName());
                    zos.putNextEntry(anEntry);
                    while ((bytesIn = fis.read(buffer)) != -1) {
                        zos.write(buffer, 0, bytesIn);
                    }
                }
            }
            return sos.getLength();
        }
    }

 

A minta tömb tömörített méretét a következő metódussal lehet meghatározni:

    public static long exactSizeOfZippedByteArray(byte[] file)
        throws IOException {
        Deflater oDeflate = new Deflater();
        oDeflate.setInput(file);
        oDeflate.finish();
        try (LenghtOutputStream los = new LenghtOutputStream();) {
            byte[] byRead = new byte[BUFFER_SIZE];
            while (!oDeflate.finished()) {
                int iBytesRead = oDeflate.deflate(byRead);
                if (iBytesRead == byRead.length) {
                    los.write(byRead);
                } else {
                    los.write(byRead, 0, iBytesRead);
                }
            }
            oDeflate.end();
            return los.getLength();
        }
    }

 

A streamek pontos ZIP-elt méret meghatározásához nem kell mást tenni, mint készíteni egy dummy OutputStream-et, amely nem tesz mást, csak megszámolja a neki átadott bájtokat:

public class LengthOutputStream extends OutputStream {

    private long length = 0L;

    @Override
    public void write(int b) throws IOException {
        length++;
    }

    public long getLength() {
        return length;
    }
}

 

LengthOutputStream-et egyszerűen átadjuk a ZipOutputStream objektumnak, így a tömörített adatfolyamot a ZipOutputStream a LengthOutputStream-nek adja át, ami megszámolja a bájtokat, és a végén le tudjuk kérdezni tőle a ZIP méretét:

public static long sizeOfZippedDirectory(File dir) throws FileNotFoundException, IOException {
    try (LengthOutputStream sos = new LengthOutputStream();
        ZipOutputStream zos = new ZipOutputStream(sos);) {
        ... // Fájlok hozzáadás a ZIP folyamhoz
        return sos.getLength();
    }
}

 

Kategória: Java

Látogatók

88277
Ma51
Tegnap96
Ezen a héten388
Ebben a hónapban1307
Összesen88277
Statistik created: 2017-11-17T18:59:48+00:00
Bejelentkezett felhasználók 0
Regisztrált felhasználók 1
Ma regisztráltak 0