1
votes

Java: getClass (). GetResource (). ToURI () Vs getClass (). GetResourceAsStream ()

J'ai un projet java modules multiples sbt et certains d'entre eux contiennent un dossier resources .

InputStream templateIS = getClass().getResourceAsStream("/template.xls");

Après l'empaquetage j'ai obtenu:

URI template = getClass().getResource("/template.xls").toURI();
Files.newInputStream(Paths.get(template), StandardOpenOption.READ);

Et j'exécute mon programme comme n'importe quelle autre application java: java -cp "lib / *" MainClass .

Mon problème est d'accéder au template.xls depuis module-2.jar.

Au début, j'ai essayé les lignes ci-dessous pour obtenir mon modèle:

lib/module-1.jar
lib/module-2.jar

En mode développement , cela fonctionne. Mais pas sur le serveur (après le déploiement), il ne trouve pas la ressource.

java.nio.file.FileSystemNotFoundException: null [jar: fichier: /.../ lib / module-1.jar! /template.xls]

Après quelques recherches, j'ai modifié mon code d'accès comme suit pour qu'il fonctionne dans les deux modes (développement et déploiement):

module-1
  resources
    template.xls
module-2
  resources
    other.xls

Je ne comprends pas pourquoi!

Quelle est la différence entre les deux méthodes?


1 commentaires

La différence est que les ressources ne sont pas des fichiers. Vous aviez déjà une URL dans le premier cas, à partir de laquelle vous auriez pu obtenir directement un InputStream , sans le détour invalide vers File et FileInputStream . Dans le second cas, vous êtes correctement allé directement au InputStream sans le détour.


3 Réponses :


2
votes

Votre premier scénario ne fonctionne pas car le template.xls est empaqueté dans un fichier jar. Ce n'est pas un fichier sur le système de fichiers (alors qu'il se trouve probablement dans votre environnement de développement avant l'empaquetage en tant que fichier). En tant que tel, l'API Files ne peut pas le trouver.

Class.getResourceAsStream () utilise le mécanisme de chargement de classe, et la classe (évidemment) est chargée à partir du fichier .jar .


3 commentaires

mais pourquoi il le fonde avec getResourceAsStream ?


l'autre chose est que other.xls est également dans le fichier jar mais je peux y accéder dans le premier scénario


@bubbles Parce que c'est à cela que sert getResourceAsStream () .



2
votes

De la documentation ,

La méthode getResource () renvoie une URL pour la ressource. L'URL (et sa représentation) est spécifique à l'implémentation et à la JVM (autrement dit, l'URL obtenue dans une instance d'exécution peut ne pas fonctionner dans un autre). Son protocole est généralement spécifique au chargement du ClassLoader la ressource. Si la ressource n'existe pas ou n'est pas visible en raison de considérations de sécurité, les méthodes renvoient null.

Si le code client veut lire le contenu de la ressource comme un InputStream, il peut appliquer la méthode openStream () sur l'URL. C'est assez commun pour justifier l'ajout de getResourceAsStream () à Class et ClassLoader. getResourceAsStream () identique à l'appel getResource (). openStream (), sauf que getResourceAsStream () intercepte Les exceptions IO renvoient un InputStream nul.

Donc, getResourceAsStream () équivaut à appeler getResource (). openStream () , sauf que getResourceAsStream () intercepte les retours d'exceptions IO un InputStream nul.


0 commentaires

3
votes

Files.newInputStream , comme son nom l'indique, peut ouvrir des fichiers. Il ne peut rien ouvrir d'autre. C'est juste pour les fichiers.

Le concept de InputStream est beaucoup plus abstrait. Lorsque vous ouvrez un fichier pour la lecture, vous obtenez un flux d'entrée, yup. Mais vous obtenez également des flux d'entrée pour bien d'autres choses: lecture à partir d'une connexion réseau; lire le contenu décompressé des fichiers zip. Lecture de la sortie d'une opération de décryptage. Le nom le dit vraiment: c'est une entrée, et c'est un flux de données. Ce qui s'applique à bien plus que «fichier sur un système de fichiers».

Paths.get (template) produit un objet chemin, qui représente un fichier sur le système de fichiers. Si template est dérivé d'un URI, cela ne fonctionne pas à moins que l'URI que vous avez ne soit un URI d'un objet fichier; la plupart des URI ne servent pas à classer les objets.

En mettant tout cela ensemble, dans votre premier échantillon, vous trouvez une ressource sur le chemin de classe (qui peut être des fichiers, mais pas nécessairement. Par exemple, il peut s'agir d'entrées dans un fichier jar), vous demandez ensuite son URI, transmettez-le à l'API Paths pour le transformer en objet Path, puis demandez à l'API Files de le transformer en InputStream, qui ne fonctionne que si l'URI représente un fichier.

Dans le deuxième extrait, vous demandez simplement au système de chargeur de classe de vous fournir un flux d'entrée. Il sait comment faire cela (après tout, java doit charger ces fichiers de classe!). Si la ressource que vous demandez se trouve être représentée par un fichier, elle va faire, en interne, plus ou moins la même chose que votre premier extrait de code: utilisez l'API Files pour ouvrir le fichier en lecture. Mais si c'est autre chose, il sait aussi comment faire cela - il sait également comment obtenir des ressources sur un réseau, à partir de fichiers jar internes, générés à la volée - le concept de chargement de classe (qui est ce que classe .getResource vous permet d'accéder) est extrait.

NB: vous l'utilisez mal. La méthode appropriée est ClassYouAreWritingIn.class.getResource et ClassYouAreWritingIn.class.getResourceAsStream ; getClass (). getResource n'est pas correct; qui casse lors du sous-classement, contrairement à la forme correcte.


0 commentaires