web-dev-qa-db-fra.com

Manière préférée d’utiliser Java ZipOutputStream et BufferedOutputStream

Dans Java est-ce que j'instancie un ZipOutputStream en premier ou le BufferedOutputStream en premier? Exemple:

FileOutputStream dest = new FileOutputStream(file);
ZipOutputStream Zip = new ZipOutputStream(new BufferedOutputStream(dest));

// use Zip output stream to write to

Ou:

FileOutputStream dest = new FileOutputStream(file);
BufferedOutputStream out = new BufferedOutputStream(new ZipOutputStream(dest));

// use buffered stream to write to

Dans mes chronologies non scientifiques, je ne peux pas sembler dire beaucoup de différence ici. Je ne vois rien dans l'API Java qui indique si l'une ou l'autre de ces méthodes est nécessaire ou préférable. Tout conseil? Il semble que compresser la sortie en premier, puis la mettre en mémoire tampon pour les écritures serait plus efficace.

52
jjathman

Vous devriez toujours envelopper le BufferedOutputStream avec le ZipOutputStream, jamais l'inverse. Voir le code ci-dessous:

FileOutputStream fos = new FileOutputStream("hello-world.Zip");
BufferedOutputStream bos = new BufferedOutputStream(fos);
ZipOutputStream zos = new ZipOutputStream(bos);

try {
    for (int i = 0; i < 10; i++) {
        // not available on BufferedOutputStream
        zos.putNextEntry(new ZipEntry("hello-world." + i + ".txt"));
        zos.write("Hello World!".getBytes());
        // not available on BufferedOutputStream
        zos.closeEntry();
    }
}
finally {
    zos.close();
}

Comme le disent les commentaires, les méthodes putNextEntry() et closeEntry() ne sont pas disponibles sur BufferedOutputStream. Sans appeler ces méthodes, ZipOutputStream lève une exception Java.util.Zip.ZipException: no current Zip entry.

Par souci d'exhaustivité, il est à noter que la clause finally appelle uniquement close() sur le ZipOutputStream. Ceci est dû au fait que, par convention, toutes les implémentations intégrées du wrapper du flux de sortie Java) propagent la fermeture.

MODIFIER

Je viens de tester l'inverse. Il s'avère que le fait d'encapsuler un ZipOutputStream avec BufferedOutputStream et de n'appeler que write() dessus (sans créer/fermer d'entrées) ne jettera pas un ZipException. Au lieu de cela, le fichier Zip résultant sera corrompu, sans aucune entrée à l'intérieur.

78
Daniel Dinnyes

Vous devriez:

ZipOutputStream out =  new ZipOutputStream(new BufferedOutputStream(dest));

parce que vous voulez mettre en tampon l'écriture sur le disque (parce que cela est beaucoup plus efficace dans les blocs de données volumineux que dans beaucoup de petits).


Cette

new BufferedOutputStream(new ZipOutputStream(dest));

serait tampon avant la compression Zip. Mais tout cela se passe dans la mémoire et n’a pas besoin de tampon car beaucoup de petits accès mémoire ont à peu près la même vitesse que quelques gros. En mémoire, le temps nécessaire est proportionnel au nombre d'octets en lecture/écriture.

Comme mentionné dans les commentaires:

Les méthodes de ZipOutputStream qui ne font pas partie de BufferedOutputStream ne seraient pas disponibles également. Par exemple. putNextEntry et closeEntry.

21
MrSmith42