9
votes

Compresser un gros fichier dans une fermeture éclair avec Java

J'ai la nécessité de comprimer un grand fichier (~ 450 Mobyte) à travers la classe Java ZipOutPutStream. Cette grosse dimension provoque un problème d'erreur "OutofMemory" de mon espace de tas JVM. Cela se produit parce que la méthode "zos.write (...)" stocke tout le contenu du fichier pour compresser dans un tableau d'octets interne avant de le comprimer.

            origin = new BufferedInputStream(fi, BUFFER);
        ZipEntry entry = new ZipEntry(filePath);
        zos.putNextEntry(entry);

        int count;
        while ((count = origin.read(data, 0, BUFFER)) != -1)
        {
            zos.write(data, 0, count);
        }
        origin.close();


0 commentaires

4 Réponses :


3
votes

Il y a une bibliothèque appelée TrueZip que j'ai utilisé avec un bon succès dans le passé pour faire ce genre de chose.

Je ne peux pas garantir que cela fait mieux sur la mémoire tampon. Je sais que cela fait beaucoup de choses avec son propre codage plutôt que dépendant de l'API ZIP de la JDK.

Alors ça vaut la peine d'essayer, à mon avis.


0 commentaires

1
votes

ZipOutPutStream est basé sur le flux, il ne tient pas la mémoire. Votre tampon peut être trop grand.


1 commentaires

Mon tampon est de 2048 octets et je ne pense pas être trop gros! C'est l'exception: exception dans le fil "Main" Java.lang.outofMemororyError: Place de tas Java à Java.Util.arrays.copyof 94) à Java.Util.zip.deflaterOutPutStream.deflate (DeflaterOutPutStr eam.java:161) à Java.Util.zip.deflaterOutPutStream.write (DeflaterOutputStrea m.java:118) à Java.Util.zip.zipOutPutStream.write (ZipOutputStream.java:272)



0
votes

Je me demande si c'est parce que vous stockez le contenu dans une ZipENTry, il charge peut-être essentiellement tout son contenu avant d'écrire la ZipENTry. Devez-vous utiliser ZIP? Si ce n'est qu'un seul flux de données, vous devez compresser, vous pouvez plutôt regarder dans la gzipoutputtream à la place. Je crois que cela n'aurait pas le même problème.

J'espère que cela aide.


2 commentaires

J'ai besoin de stocker un contenu d'annuaire dans un fichier ZIP pour envoyer via un service Web.


Cela ressemble à une mauvaise idée si vous avez des objets aussi importants dans votre réponse. Envisagez de retourner une URL à la place d'où le fichier ZIP peut être retransmis. Les servlets simples permettent une réponse en streaming basée sur des octets.



11
votes

Selon votre commentaire à la réponse de Sam, vous avez manifestement créé un zipOutputStream, qui enveloppe une byearrayOutPutStream. Le byearrayOutPutStream de bien sûr cache le résultat compressé en mémoire. Si vous le souhaitez écrit sur le disque, vous devez envelopper le zipOutputStream autour d'un fichier de fichiers.


3 commentaires

Ok, je comprends ce que vous m'avez dit, mais les données comprimées sont d'environ 60 Mo ... Tot faible pour exécuter une erreur de tas "Outofspace". Qu'en est-il? Je dois mettre un XMX1024M pour être bon! Est probablement une mon erreur!


+1, Utilisez un fichier de fichiers-vente pour écrire le zip sur le disque ou si vous souhaitez la diffuser directement sur le navigateur, utilisez la sortie HTTPServletResponse.


Lorsque 60 mbytes ont explosé la mémoire utilisez-vous les paramètres JVM par défaut? Si oui, alors cela sonne à peu près bien. Même si votre JVM fonctionne à une taille de tas de 64 m à un moment donné, la byteArrayOutputStream devra développer ce tableau d'octets [] ... ce qui signifie une copie complète.