web-dev-qa-db-fra.com

Comment obtenir un chemin d'accès à une ressource dans un fichier JAR Java

J'essaie d'obtenir un chemin vers une ressource mais je n'ai pas eu de chance. 

Cela fonctionne (à la fois dans IDE et avec le fichier JAR), mais de cette manière, je ne peux pas obtenir un chemin d'accès à un fichier, seul le contenu du fichier: 

ClassLoader classLoader = getClass().getClassLoader();
PrintInputStream(classLoader.getResourceAsStream("config/netclient.p"));

Si je fais ça:

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("config/netclient.p").getFile());

Le résultat est: Java.io.FileNotFoundException: file:/path/to/jarfile/bot.jar!/config/netclient.p (No such file or directory)

Est-il possible d'obtenir un chemin d'accès à un fichier de ressources?

145
no_ripcord

C'est délibéré. Le contenu du "fichier" peut ne pas être disponible sous forme de fichier. N'oubliez pas que vous traitez avec des classes et des ressources pouvant faire partie d'un fichier JAR ou d'un autre type de ressource. Le chargeur de classes n'a pas à fournir de descripteur de fichier à la ressource. Par exemple, le fichier jar n'a peut-être pas été développé en fichiers individuels dans le système de fichiers.

Tout ce que vous pouvez faire en obtenant un fichier Java.io.File peut être fait en copiant le flux dans un fichier temporaire et en faisant de même, si un fichier Java.io.File est absolument nécessaire.

67
Neal Maloney

Lorsque vous chargez une ressource, assurez-vous de noter la différence entre:

getClass().getClassLoader().getResource("com/myorg/foo.jpg") //relative path

et 

getClass().getResource("/com/myorg/foo.jpg")); //note the slash at the beginning

J'imagine que cette confusion est à l'origine de la plupart des problèmes lors du chargement d'une ressource. 


De plus, lorsque vous chargez une image, il est plus facile d'utiliser getResourceAsStream():

BufferedImage image = ImageIO.read(getClass().getResourceAsStream("/com/myorg/foo.jpg"));

Lorsque vous devez réellement charger un fichier (non-image) à partir d'une archive JAR, vous pouvez essayer ceci:

    File file = null;
    String resource = "/com/myorg/foo.xml";
    URL res = getClass().getResource(resource);
    if (res.getProtocol().equals("jar")) {
        try {
            InputStream input = getClass().getResourceAsStream(resource);
            file = File.createTempFile("tempfile", ".tmp");
            OutputStream out = new FileOutputStream(file);
            int read;
            byte[] bytes = new byte[1024];

            while ((read = input.read(bytes)) != -1) {
                out.write(bytes, 0, read);
            }
            out.close();
            file.deleteOnExit();
        } catch (IOException ex) {
            Exceptions.printStackTrace(ex);
        }
    } else {
        //this will probably work in your IDE, but not from a JAR
        file = new File(res.getFile());
    }

    if (file != null && !file.exists()) {
        throw new RuntimeException("Error: File " + file + " not found!");
    }
50
Tombart

La réponse en une ligne est - 

String path = this.getClass().getClassLoader().getResource(<resourceFileName>).toExternalForm()

En gros, la méthode getResource donne l'URL. À partir de cette URL, vous pouvez extraire le chemin en appelant toExternalForm()

Références:

getResource () , toExternalForm ()

20
Manojkumar Khotele

J'ai passé un moment à déconner avec ce problème, parce qu'aucune solution que j'ai trouvée ne fonctionnait réellement, assez étrangement! Le répertoire de travail n’est souvent pas le répertoire du fichier JAR, en particulier si un fichier JAR (ou tout autre programme) est exécuté à partir du menu Démarrer de Windows. Voici donc ce que j'ai fait et cela fonctionne pour les fichiers .class exécutés à l'extérieur d'un fichier JAR aussi bien que pour un fichier JAR. (Je ne l'ai testé que sous Windows 7.)

try {
    //Attempt to get the path of the actual JAR file, because the working directory is frequently not where the file is.
    //Example: file:/D:/all/Java/TitanWaterworks/TitanWaterworks-en.jar!/TitanWaterworks.class
    //Another example: /D:/all/Java/TitanWaterworks/TitanWaterworks.class
    PROGRAM_DIRECTORY = getClass().getClassLoader().getResource("TitanWaterworks.class").getPath(); // Gets the path of the class or jar.

    //Find the last ! and cut it off at that location. If this isn't being run from a jar, there is no !, so it'll cause an exception, which is fine.
    try {
        PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('!'));
    } catch (Exception e) { }

    //Find the last / and cut it off at that location.
    PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('/') + 1);
    //If it starts with /, cut it off.
    if (PROGRAM_DIRECTORY.startsWith("/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(1, PROGRAM_DIRECTORY.length());
    //If it starts with file:/, cut that off, too.
    if (PROGRAM_DIRECTORY.startsWith("file:/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(6, PROGRAM_DIRECTORY.length());
} catch (Exception e) {
    PROGRAM_DIRECTORY = ""; //Current working directory instead.
}
11
DeProgrammer

si netclient.p se trouve dans un fichier JAR, il n'y aura pas de chemin car ce fichier se trouve dans un autre fichier. dans ce cas, le meilleur chemin que vous pouvez avoir est vraiment file:/path/to/jarfile/bot.jar!/config/netclient.p.

8
cd1

Vous devez comprendre le chemin dans le fichier jar.
Il suffit de s'y référer relatif. Donc, si vous avez un fichier (myfile.txt), situé dans foo.jar dans le répertoire \src\main\resources (style maven). Vous vous y référeriez comme:

src/main/resources/myfile.txt

Si vous videz votre fichier jar en utilisant jar -tvf myjar.jar, vous verrez la sortie et le chemin relatif dans le fichier jar, et vous utiliserez FORWARD SLASHES.

6
eric manley

Il s'agit du même code d'utilisateur Tombart avec flux et fermeture de flux afin d'éviter la copie incomplète du contenu du fichier temporaire à partir de la ressource jar et d'avoir des noms de fichier temporaires uniques.

     File file = null;
        String resource = "/view/Trial_main.html" ;
        URL res = getClass().getResource(resource);
        if (res.toString().startsWith("jar:")) {
            try {
                InputStream input = getClass().getResourceAsStream(resource);
                file = File.createTempFile(new Date().getTime()+"", ".html");
                OutputStream out = new FileOutputStream(file);
                int read;
                byte[] bytes = new byte[1024];

                while ((read = input.read(bytes)) != -1) {
                    out.write(bytes, 0, read);
                }
                out.flush();
                out.close();
                input.close();
                file.deleteOnExit();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        } else {
            //this will probably work in your IDE, but not from a JAR
            file = new File(res.getFile());
        }
2
Bruce

Dans mon cas, j'ai utilisé un objet URL à la place de Path.

Fichier

File file = new File("my_path");
URL url = file.toURI().toURL();

Ressource dans classpath utilisant classloader

URL url = MyClass.class.getClassLoader().getResource("resource_name")

Lorsque je dois lire le contenu, je peux utiliser le code suivant:

InputStream stream = url.openStream();

Et vous pouvez accéder au contenu à l'aide d'un InputStream.

2
jmgoyesc

Un fichier est une abstraction pour un fichier dans un système de fichiers et les systèmes de fichiers ne savent rien du contenu d'un fichier JAR.

Essayez avec un URI, je pense qu’il existe un protocole jar: // qui pourrait être utile pour vos clients.

2
fortran

Dans votre dossier de ressources (Java/main/resources) de votre jar, ajoutez votre fichier (nous supposons que vous avez ajouté un fichier xml nomméimports.xml), après quoi vous injectez ResourceLoader si vous utilisez spring. comme ci-dessous 

@Autowired
private ResourceLoader resourceLoader;

inside tour function écris le code ci-dessous pour charger le fichier:

    Resource resource = resourceLoader.getResource("classpath:imports.xml");
    try{
        File file;
        file = resource.getFile();//will load the file
...
    }catch(IOException e){e.printStackTrace();}
1
private static final String FILE_LOCATION = "com/input/file/somefile.txt";

//Method Body


InputStream invalidCharacterInputStream = URLClassLoader.getSystemResourceAsStream(FILE_LOCATION);

Obtenir ceci degetSystemResourceAsStreamest la meilleure option. En obtenant le flux d'entrée plutôt que le fichier ou l'URL, fonctionne dans un fichier JAR et de manière autonome.

1
Shano

C'est peut-être un peu tard mais vous pouvez utiliser ma bibliothèque KResourceLoader pour obtenir une ressource de votre jar:

File resource = getResource("file.txt")
1
Lamberto Basti

Le chemin suivant a fonctionné pour moi: classpath:/path/to/resource/in/jar

1
Anatoly

Ce n’est pas le moyen optimal de charger des ressources, at-il été précisé, mais si vous devez absolument avoir une référence Java.io.File, essayez alors de:

 URL url = null;
  try {
     URL baseUrl = YourClass.class.getResource(".");
     if (baseUrl != null) {
        url = new URL(baseUrl, "yourfilename.ext");
     } else {
        url = YourClass.class.getResource("yourfilename.ext");
     }
  } catch (MalformedURLException e) {
     // Do something appropriate
  }

Cela vous donne un Java.net.URL et il peut être utilisé dans un constructeur Java.io.File.

1
Jes

Dans un fichier JAR, la ressource est située absolument dans la hiérarchie des packages (pas dans le système de fichiers). Ainsi, si vous avez la classe com.example.Sweet chargeant une ressource nommée "./default.conf", le nom de la ressource est alors spécifié "/com/example/default.conf". 

Mais si c'est dans un pot, alors ce n'est pas un fichier ...

0
Vilnis Krumins

Peut-être que cette méthode peut être utilisée pour une solution rapide.

public static String getResourcePath(String relativePath)
{
    String pathStr = null;
    URL location = <Class>.class.getProtectionDomain().getCodeSource().getLocation();
    String codeLoaction = location.toString();
    try{
        if (codeLocation.endsWith(".jar"){
            //Call from jar
            Path path = Paths.get(location.toURI()).resolve("../classes/" + relativePath).normalize();
            pathStr = path.toString();
        }else{
            //Call from IDE
            pathStr = <Class>.class.getClassLoader().getResource(relativePath).getPath();
        }
    }catch(URISyntaxException ex){
        ex.printStackTrace();
    }
    return pathStr;
}
0
gbii