web-dev-qa-db-fra.com

getResourceAsStream renvoie la valeur null

Je charge un fichier texte depuis un package dans un fichier JAR compilé de mon projet Java. La structure de répertoire pertinente est la suivante:

/src/initialization/Lifepaths.txt

Le code utilisé pour charger le fichier est:

public class Lifepaths {
    public static void execute() {
        System.out.println(Lifepaths.class.getClass().
            getResourceAsStream("/initialization/Lifepaths.txt"));
    }

    private Lifepaths() {}

    //This is temporary; will eventually be called from outside
    public static void main(String[] args) {execute();}
}

L'impression imprimera toujours null, peu importe ce que j'utilise. Je ne sais pas pourquoi cela ne marche pas, alors j'ai aussi essayé:

  • "/src/initialization/Lifepaths.txt"
  • "initialization/Lifepaths.txt"
  • "Lifepaths.txt"

Ni l'un ni l'autre ne fonctionne. J'ailude nombreusesquestions jusqu'à présent sur le sujet, mais aucune d'entre elles n'a été utile - en général, elles recommandent simplement de charger les fichiers à l'aide du chemin racine, qui Je fais déjà. Cela, ou chargez simplement le fichier à partir du répertoire en cours (chargez simplement filename), que j'ai également essayé. Le fichier est compilé dans le fichier JAR à l'emplacement approprié avec le nom approprié. 

Comment résoudre ce problème?

135
Zyerah

Lifepaths.class.getClass().getResourceAsStream(...) charge les ressources à l'aide du chargeur de classes du système. Il échoue évidemment car il ne voit pas vos fichiers JAR.

Lifepaths.class.getResourceAsStream(...) charge les ressources à l'aide du même chargeur de classe que celui qui a chargé Lifepaths et il devrait avoir accès aux ressources de vos fichiers JAR.

125
hoaz

Les règles sont les suivantes:

  1. vérifiez l'emplacement du fichier que vous souhaitez charger dans le fichier JAR (et assurez-vous qu'il a bien été ajouté au fichier JAR)
  2. utilisez soit un chemin absolu: chemin commence à la racine du fichier JAR
  3. utilisez un chemin relatif: chemin commence dans le répertoire du paquet de la classe que vous appelez getResource/getResoucreAsStream

Et essaye:

Lifepaths.class.getResourceAsStream("/initialization/Lifepaths.txt")

au lieu de

Lifepaths.class.getClass().getResourceAsStream("/initialization/Lifepaths.txt")

(Je ne sais pas si cela fait une différence, mais le premier utilisera le bon ClassLoader/JAR, alors que je ne suis pas sûr du dernier)

50
Puce

Il existe donc plusieurs façons d’obtenir une ressource à partir d’un fichier jar, chacune d’elles ayant une syntaxe légèrement différente, le chemin devant être spécifié différemment.

La meilleure explication que j'ai vue est cet article de JavaWorld . Je vais résumer ici, mais si vous voulez en savoir plus, vous devriez consulter l'article.

Les méthodes

1) ClassLoader.getResourceAsStream()

Format: "/" - noms séparés; pas de "/" (tous les noms sont absolus). 

Exemple: this.getClass().getClassLoader().getResourceAsStream("some/pkg/resource.properties");

2) Class.getResourceAsStream()

Format: "/" - noms séparés; "/" en tête indique les noms absolus; tous les autres noms sont relatifs au paquet de la classe

Exemple: this.getClass().getResourceAsStream("/some/pkg/resource.properties");

40
greedybuddha

N'utilisez pas de chemins absolus, comparez-les au répertoire "ressources" de votre projet. Code rapide et sale qui affiche le contenu de MyTest.txt à partir du répertoire 'resources'.

@Test
public void testDefaultResource() {
    // can we see default resources
    BufferedInputStream result = (BufferedInputStream) 
         Config.class.getClassLoader().getResourceAsStream("MyTest.txt");
    byte [] b = new byte[256];
    int val = 0;
    String txt = null;
    do {
        try {
            val = result.read(b);
            if (val > 0) {
                txt += new String(b, 0, val);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } 
    } while (val > -1);
    System.out.println(txt);
}
12
Paul Smith

Vous voudrez peut-être essayer ceci pour obtenir le flux, c’est d’abord obtenir l’URL puis l’ouvrir en tant que flux. 

URL url = getClass().getResource("/initialization/Lifepaths.txt"); 
InputStream strm = url.openStream(); 

Une fois, j'avais une question similaire: La lecture du fichier txt de jar échoue mais la lecture de l'image fonctionne

9
MrD

Il semble y avoir un problème avec le ClassLoader que vous utilisez. Utilisez contextClassLoader pour charger la classe. Ceci indépendamment du fait que ce soit dans une méthode statique/non statique

Thread.currentThread().getContextClassLoader().getResourceAsStream......

6
Binita Bharati

Je ne sais pas si cela m'aide, mais dans mon cas, ma ressource se trouvait dans le dossier/src/et cette erreur me renvoyait . J'ai ensuite déplacé l'image dans le dossier bin et le problème a été résolu.

2
Leo Ufimtsev

Assurez-vous que votre répertoire de ressources (par exemple "src") se trouve dans votre chemin de classe (assurez-vous qu'il s'agit d'un répertoire source dans votre chemin de construction dans Eclipse).

Assurez-vous que clazz est chargé à partir du chargeur de classes principal.

Ensuite, pour charger src/initialization/Lifepaths.txt, utilisez 

clazz.getResourceAsStream("/initialization/Lifepaths.txt");

Pourquoi: clazz.getResourcesAsStream(foo) cherche foo dans dans le chemin de classe de clazz , par rapport au répertoire dans lequel clazz habite . Le "/" initial le fait charger à partir de la racine de n’importe quel répertoire du classpath de clazz.

À moins que vous ne soyez dans un conteneur quelconque, comme Tomcat, ou que vous fassiez directement quelque chose avec les chargeurs de classe, vous pouvez simplement traiter votre chemin de classe Eclipse/en ligne de commande comme le seul chemin de classe classloader.

2
Bobby Martin

Je me suis retrouvé dans un problème similaire. Depuis que j'utilise maven, je devais mettre à jour mon pom.xml pour y inclure quelque chose comme:

   ...
</dependencies>
<build>
    <resources>
        <resource>
            <directory>/src/main/resources</directory>
        </resource>
        <resource>
            <directory>../src/main/resources</directory>
        </resource>
    </resources>
    <pluginManagement>
        ...

Notez la balise de ressource ici pour spécifier où se trouve ce dossier. Si vous avez des projets imbriqués (comme je le fais), vous souhaiterez peut-être obtenir des ressources d'autres zones que du module dans lequel vous travaillez. Cela permet d'éviter de conserver le même fichier dans chaque référentiel si vous utilisez des données de configuration similaires. 

1
plosco

Dans mon cas, rien ne fonctionnait à moins que je supprime les espaces des noms de fichiers ...

0
user3563159

Ce qui a fonctionné pour moi a été d’ajouter le fichier sous Mon projet/Ressources Java/src, puis d’utiliser 

this.getClass().getClassLoader().getResourceAsStream(myfile.txt);

Je n'ai pas eu besoin d'ajouter explicitement ce fichier au chemin (l'ajouter à/src le fait apparemment)

0
Pablo

Le chargeur de classe JVM par défaut utilisera parent-classloader pour charger les ressources en premier: deletegate-parent-classloader.

Le chargeur de classes de Lifepaths.class.getClass() est bootstrap classloader, donc getResourceAsStream ne cherchera que $ Java_HOME, quel que soit l'utilisateur fourni par classpath. De toute évidence, Lifepaths.txt n’est pas là.

Le chargeur de classe de Lifepaths.class est system classpath classloader, donc getResourceAsStream recherchera le classpath défini par l'utilisateur et Lifepaths.txt sera présent.

Lorsque vous utilisez Java.lang.Class#getResourceAsStream(String name), le nom qui ne commence pas par '/' sera ajouté avec le préfixe package name. Si vous voulez éviter cela, veuillez utiliser Java.lang.ClassLoader#getResourceAsStream. Par exemple:

ClassLoader loader = Thread.currentThread().getContextClassLoader();
String resourceName = "Lifepaths.txt";
InputStream resourceStream = loader.getResourceAsStream(resourceName); 
0
ridox