8
votes

Mauvaise performance des utilitaires décisifs de Java

J'ai remarqué que l'installation de décompressement de Java est extrêmement lente par rapport à l'utilisation d'un outil natif tel que Winzip.

Y a-t-il une bibliothèque tierce disponible pour Java qui est plus efficace? Open Source est préférable. P>

edit forte> p>

Voici une comparaison de vitesse à l'aide de la solution intégrée Java vs 7zip. J'ai ajouté des flux d'entrée / sortie tamponnés dans ma solution d'origine (merci Jim, cela a fait une grande différence). P>

Taille du fichier zip: 800k Solution Java: 2,7 secondes 7ZIP Solution: 204 ms p>

Voici le code modifié à l'aide de la décompression Java intégrée: P>

/** Unpacks the give zip file using the built in Java facilities for unzip. */
@SuppressWarnings("unchecked")
public final static void unpack(File zipFile, File rootDir) throws IOException
{
  ZipFile zip = new ZipFile(zipFile);
  Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) zip.entries();
  while(entries.hasMoreElements()) {
    ZipEntry entry = entries.nextElement();
    java.io.File f = new java.io.File(rootDir, entry.getName());
    if (entry.isDirectory()) { // if its a directory, create it
      continue;
    }

    if (!f.exists()) {
      f.getParentFile().mkdirs();
      f.createNewFile();
    }

    BufferedInputStream bis = new BufferedInputStream(zip.getInputStream(entry)); // get the input stream
    BufferedOutputStream bos = new BufferedOutputStream(new java.io.FileOutputStream(f));
    while (bis.available() > 0) {  // write contents of 'is' to 'fos'
      bos.write(bis.read());
    }
    bos.close();
    bis.close();
  }
}


4 commentaires

Je n'ai eu aucun problème avec les fonctions UNZIPIP, et j'ai traité 250 Mo de fichiers ZIP contenant des fichiers texte gzippés. Que fais-tu ça prend si longtemps? Est-ce quelque chose de complexe?


Peut-être que si vous le faites dans un fil à faible priorité?


Je recommande fortement: si (entrée.getName (). Contient ("..")) Continuer;


La réponse à cette question est utile mais l'utilité n'a aucune relation avec la question (puisque la question elle-même était incorrecte). Je suis tenté d'aller changer le quesiton à "Pourquoi mon code Java décompressé est-il si lent" pour aider les futurs chercheurs ... La meilleure réponse est excellente cependant. Serait-ce une mauvaise idée pour moi d'aller et de changer la question?


3 Réponses :


3
votes

Assurez-vous d'alimenter la méthode de décompression d'une bufferedInPutStream dans votre application Java. Si vous avez commis l'erreur d'utiliser un flux d'entrée non coupé, votre performance IO est garantie de sucer.


0 commentaires

0
votes

J'ai trouvé une solution "inélégant". Il existe une utilitaire open source 7zip (www.7-zip.org) qui est libre d'utiliser. Vous pouvez télécharger la version de la ligne de commande ( http://www.7-zip.org/download. HTML ). 7-Zip est uniquement pris en charge sur Windows, mais on dirait que cela a été porté sur d'autres plates-formes (P7Zip).

Évidemment, cette solution n'est pas idéale car elle est spécifique et repose sur un exécutable. Cependant, la vitesse comparée à faire le décompression en Java est incroyable. P>

Voici le code de la fonction utilitaire que j'ai créée pour interfacer avec cet utilitaire. Il y a place à l'amélioration lorsque le code ci-dessous est spécifique Windows. P>

/** Unpacks the zipfile to the output directory.  Note: this code relies on 7-zip 
   (specifically the cmd line version, 7za.exe).  The exeDir specifies the location of the 7za.exe utility. */
public static void unpack(File zipFile, File outputDir, File exeDir) throws IOException, InterruptedException
{
  if (!zipFile.exists()) throw new FileNotFoundException(zipFile.getAbsolutePath());
  if (!exeDir.exists()) throw new FileNotFoundException(exeDir.getAbsolutePath());
  if (!outputDir.exists()) outputDir.mkdirs();

  String cmd = exeDir.getAbsolutePath() + "/7za.exe -y e " + zipFile.getAbsolutePath();

  ProcessBuilder builder = new ProcessBuilder(new String[] { "cmd.exe", "/C", cmd });
  builder.directory(outputDir);
  Process p = builder.start();
  int rc = p.waitFor();
  if (rc != 0) {
    log.severe("Util::unpack() 7za process did not complete normally.  rc: " + rc);
  }
}      


0 commentaires

24
votes

Le problème n'est pas le décompression, c'est la manière inefficace que vous écrivez les données décompressées sur le disque. Mes points de repère montrent que l'utilisation de xxx

réduit la durée d'exécution de la méthode d'un facteur de 5 (de 5 à 1 seconde pour un fichier zip de 6 Mo).

Le probable Culprit est votre utilisation de bis.Available () . En plus d'être incorrect (disponible renvoie le nombre d'octets jusqu'à ce qu'un appel à lire bloquerait, non jusqu'à la fin du flux), cela contourne la mise en mémoire tampon fournie par BufferedInPutStream, nécessitant un appel de système natif pour chaque octet copié dans le fichier de sortie.

Notez que l'enveloppement dans une bufferedream n'est pas nécessaire si vous utilisez les méthodes de lecture et d'écriture en vrac, comme je le fais ci-dessus et que le code pour fermer les ressources n'est pas sûr (si la lecture ou l'écriture échoue pour tout Raison, ni est ni os serait fermé). Enfin, si vous avez IOUTILS DANS LE PATH DE LA CLASSE, je vous recommande d'utiliser leur bien testé ioutils.Copy au lieu de rouler le vôtre. >


1 commentaires

Merci Meriton! J'ai essayé cela et la performance est maintenant comparable à 7ZIP. J'ai ajouté IOUTILS à ma boîte à outils pour l'avenir. C'est une très bonne suggestion.