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

Támogasd munkánkat!

Blogunkat nonprofit módon, teljesen ingyen készítjük, már 7 éve. Ingyenes szoftvereket biztosítunk több száz cég számára, és természetvédelmi tevékenységet is végzünk. Ezekből semmilyen bevételünk nem származik. De mi is csak pénzből tudjuk magunkat fenntartani. Azért gyűjtünk, hogy tovább tudjuk folytatni hasznos értékteremtő munkánkat, ezért kérünk, ha van 1000 - 5000 Ft-od, amit fel tudsz ajánlani számunkra, támogass minket!

Cégünk: Völgyerdő Nonprofit Kft.

Számlaszámunk: 11749015-28535807 (OTP Bank)

 

Látogatók

133127
Ma19
Tegnap32
Ezen a héten276
Ebben a hónapban1025
Összesen133127
Statistik created: 2019-09-22T02:53:15+00:00
Bejelentkezett felhasználók 0
Regisztrált felhasználók 1
Ma regisztráltak 0