2009-02-12 6 views
2

J'étends une classe utilitaire qui regroupe un ensemble d'images et de fichiers de description .xml. Actuellement, je garde tous les fichiers dans un répertoire et les charge à partir de là. Le répertoire ressemble à ceci:Extraire des fichiers d'un Jar plus efficacement

8.png 
8.xml 
9.png 
9.xml 
10.png 
10.xml 
... 
... 
50.png 
50.xml 
... 



Voici mon constructeur actuel. Il est rapide comme l'éclair et fait ce que j'ai besoin de faire. (Je l'ai déshabillé certains de l'erreur de vérification pour le rendre plus facile à lire):

public DivineFont(String directory) { 

    File dir = new File(directory); 

    //children is an array that looks like this: '10.fnt', '11.fnt', etc. 
    String[] children = dir.list(fntFileFilter); 

    fonts = new Hashtable<Integer, AngelCodeFont>(100); 

    AngelCodeFont buffer; 
    int number; 
      String fntFile; 
      String imgFile; 

    for(int k = 0; k < children.length; k++) { 
     number = Integer.parseInt(children[k].split("\\.")[0]); 
     fntFile = directory + File.separator + number + ".xml"; 
     imgFile = directory + File.separator + number + ".png"; 
     buffer = new AngelCodeFont(fntFile, imgFile); 

     fonts.put(number, buffer); 
    } 
} 

Par souci de webstart et de la propreté, j'ai essayé de charger ces ressources à partir d'un pot à la place . Je l'ai fonctionné, mais le temps de chargement est passé de instantané à quelques secondes, et ce n'est pas acceptable. Voici le code que j'ai essayé (encore une fois, la vérification d'erreurs dépouilla):.

(Ce n'est pas mieux façon de faire ce que je veux faire, c'est une maquette pour voir si l'idée a travaillé Il n » ai pas . t les deux boucles for est en aucun cas la source du problème, c'est le processus de création de tous ces InputStreams qu'il ralentit)

public DivineFont(String jarFileName) { 

    JarFile jarfile = new JarFile(jarFileName); 
    Enumeration<JarEntry> em = jarfile.entries(); 
    ArrayList<Integer> fontHeights = new ArrayList<Integer>(100); 
    for (Enumeration em1 = jarfile.entries(); em1.hasMoreElements();) { 
     String fileName = em1.nextElement().toString(); 
     if(fileName.endsWith(".fnt")) { 
      fontHeights.add(Integer.parseInt(fileName.split("\\.")[0])); 
     } 
    } 

    fonts = new Hashtable<Integer, AngelCodeFont>(100); 

    AngelCodeFont buffer; 
    int number; 

    for(int k = 0; k < fontHeights.size(); k++) { 
     number = fontHeights.get(k); 
     InputStream fntFileStream = jarfile.getInputStream(jarfile.getEntry(number + ".xml")); 
     InputStream pngFileStream = jarfile.getInputStream(jarfile.getEntry(number + ".png")); 
     buffer = new AngelCodeFont(String.valueOf(number), fntFileStream, pngFileStream); 

     fonts.put(number, buffer); 


    } 
} 


Quelqu'un sait d'une meilleure façon de travailler avec des fichiers .jar en plus de la façon dont j'ai essayé ici? Voici le AngelCodeFont API. Si c'était absolument nécessaire, je pourrais soumettre un patch pour ça, mais je préférerais ne pas le faire. Il me semble qu'il y a probablement un moyen de faire ce que je veux faire, je ne le connais tout simplement pas. Je ne suis pas très contre de rapidement jeter le fichier jar dans un répertoire temporaire, puis de lire les fichiers à partir de là, mais s'il y a un moyen de le lire directement depuis le pot rapidement, je préfèrerais le faire.

Aussi: La compression n'est pas un problème du tout. La seule raison pour laquelle j'utilise un pot est pour le problème d'emballage.

Répondre

1

Eh bien, j'ai trouvé la réponse. La réponse à ma question initiale était "Mauvaise question". Le fichier Jar n'était pas le problème, c'était la bibliothèque que j'utilisais pour charger les images.

Lorsque je chargais à partir du système de fichiers, l'image s'appelait "38.png", etc. Lorsque je chargais depuis le Jar, je l'appelais simplement "38".

La classe Image loader à l'intérieur de la bibliothèque utilise l'extension de fichier du nom pour identifier le chargeur d'image à utiliser. S'il n'y a pas d'extension de fichier, il utilise un chargeur d'images de base plus lent. Quand j'ai changé cette ligne:

buffer = new AngelCodeFont(String.valueOf(number), fntFileStream, pngFileStream); 

à cette ligne:

buffer = new AngelCodeFont(number + ".png", fntFileStream, pngFileStream); 

Nous avons nous un gagnant.

Merci pour l'aide de toute façon les gars. Il m'a fallu quelques heures pour comprendre cela, mais si ce n'était pour vos messages, j'aurais probablement continué à supposer que c'était Java plutôt que la bibliothèque que j'utilise.

-2

This library peut ne pas compresser autant que vous avez besoin, mais ça va être plus rapide ...

+0

La compression n'est pas le problème. Facilité d'utilisation pour Webstart. C'est pourquoi je veux le mettre dans un pot. Merci quand même. :-) – JoshuaD

4

Ouverture un fichier JAR est une opération très coûteuse. Vous pouvez donc ouvrir le fichier JAR une fois et conserver l'instance JarFile dans un champ statique quelque part. Dans votre cas, vous souhaiterez également lire toutes les entrées et les conserver dans un hashmap pour un accès instantané à la ressource dont vous avez besoin.

Une autre solution est de mettre le JAR dans le classpath et utiliser

DivineFont.class.getContextClassLoader().getResource*("/8.png"); 

Mind the "/"! Si vous l'omettez, Java va chercher dans le même répertoire (le paquet) dans lequel il trouve le fichier DivineFont.class.

Obtenir des choses du classpath a été optimisé à mort en Java.

+0

Cela ne renvoie qu'une URL, ce qui ne me fait pas du bien. Les constructeurs AngelCodeFont ne prennent pas en charge les URL, et dans les deux cas, s'il le faisait, il créait toujours deux nouveaux InputStreamReaders chaque fois que le constructeur était appelé. – JoshuaD

+0

Ensuite, utilisez getResourceAsStream(). –

+0

Les InputStreamReaders sont bon marché; ce qui te tue est la ligne avec le nouveau JarFile(). –

0

manipulation de fichier Jar peut être très coûteux, et la bibliothèque de classes Java implémente déjà ce type de chargement des ressources (probablement aussi efficace que possible.)

De plus, une fois que vous êtes dans webstart, vos noms de fichier jar se faire mutiler, donc vous finirez probablement par devoir explorer chaque fichier jar sur le classpath pour charger vos ressources (je l'ai fait!

Utilisez à la place Class.getResourceAsStream(String resourceName). Je ne l'ai pas profilé, mais je n'ai pas remarqué qu'il soit sensiblement plus lent que l'accès direct aux fichiers.

+0

Merci Jared. Je suis au travail maintenant, mais je vais essayer ça ce soir. Je vais vous laisser savoir comment ça se passe. – JoshuaD

Questions connexes