it-swarm.com.de

So erhalten Sie einen Pfad zu einer Ressource in einer Java-JAR-Datei

Ich versuche einen Weg zu einer Ressource zu finden, aber ich hatte kein Glück. 

Dies funktioniert (sowohl in IDE als auch mit dem JAR), aber auf diese Weise kann ich keinen Pfad zu einer Datei erhalten, nur den Inhalt der Datei: 

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

Wenn ich das mache:

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

Das Ergebnis ist: Java.io.FileNotFoundException: file:/path/to/jarfile/bot.jar!/config/netclient.p (No such file or directory)

Gibt es eine Möglichkeit, einen Pfad zu einer Ressourcendatei zu erhalten?

145
no_ripcord

Das ist absichtlich. Der Inhalt der "Datei" ist möglicherweise nicht als Datei verfügbar. Denken Sie daran, dass Sie mit Klassen und Ressourcen zu tun haben, die Teil einer JAR-Datei oder einer anderen Art von Ressource sein können. Der Classloader muss der Ressource kein Dateikennwort bereitstellen. Beispielsweise wurde die JAR-Datei möglicherweise nicht in einzelne Dateien im Dateisystem erweitert.

Alles, was Sie tun können, indem Sie eine Java.io.File erhalten, können Sie tun, indem Sie den Stream in eine temporäre Datei kopieren und dasselbe tun, wenn eine Java.io.File unbedingt erforderlich ist.

67
Neal Maloney

Achten Sie beim Laden einer Ressource auf den Unterschied zwischen:

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

und 

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

Ich denke, diese Verwirrung verursacht die meisten Probleme beim Laden einer Ressource. 


Wenn Sie ein Bild laden, ist es einfacher, getResourceAsStream() zu verwenden:

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

Wenn Sie wirklich eine (Nicht-Image-) Datei aus einem JAR-Archiv laden müssen, versuchen Sie Folgendes:

    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

Die einzeilige Antwort lautet - 

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

Grundsätzlich gibt die getResource-Methode die URL an. Von dieser URL können Sie den Pfad extrahieren, indem Sie toExternalForm() aufrufen.

Verweise:

getResource () , toExternalForm ()

20

Ich habe eine Weile mit diesem Problem herumgespielt, denn keine Lösung, die ich gefunden habe, hat seltsamerweise funktioniert! Das Arbeitsverzeichnis ist häufig nicht das Verzeichnis der JAR, insbesondere wenn eine JAR (oder ein anderes Programm) aus dem Startmenü unter Windows ausgeführt wird. Ich habe also folgendes getan, und es funktioniert für .class-Dateien, die von außerhalb eines JAR ausgeführt werden, genauso wie es für einen JAR funktioniert. (Ich habe es nur unter Windows 7 getestet.)

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

wenn sich netclient.p in einer JAR-Datei befindet, hat sie keinen Pfad, da sich diese Datei in einer anderen Datei befindet. In diesem Fall ist der beste Pfad, den Sie haben können, wirklich file:/path/to/jarfile/bot.jar!/config/netclient.p.

8
cd1

Sie müssen den Pfad in der JAR-Datei verstehen.
Beziehen Sie sich einfach relativ darauf. Wenn Sie also eine Datei (myfile.txt) haben, die sich in foo.jar im Verzeichnis \src\main\resources befindet (Maven-Stil). Sie würden sich darauf beziehen wie:

src/main/resources/myfile.txt

Wenn Sie Ihr jar mit jar -tvf myjar.jar ausgeben, werden die Ausgabe und der relative Pfad in der jar-Datei angezeigt und die FORWARD SLASHES verwendet.

6
eric manley

Dies ist derselbe Code von Benutzer Tombart mit Stream Flush und Close, um das Kopieren unvollständiger temporärer Dateiinhalte aus der JAR-Ressource zu vermeiden und eindeutige temporäre Dateinamen zu erhalten.

     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

In meinem Fall habe ich anstelle von Path ein URL-Objekt verwendet.

Datei

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

Ressource im Klassenpfad mit Classloader

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

Wenn ich den Inhalt lesen muss, kann ich den folgenden Code verwenden:

InputStream stream = url.openStream();

Und Sie können über einen InputStream auf den Inhalt zugreifen.

2
jmgoyesc

Eine Datei ist eine Abstraktion für eine Datei in einem Dateisystem, und die Dateisysteme wissen nichts über den Inhalt einer JAR-Datei.

Versuchen Sie es mit einer URI. Ich glaube, es gibt ein jar: // -Protokoll, das für Ihre Zwecke nützlich sein könnte.

2
fortran

Fügen Sie in Ihrem Ressourcenordner (Java/main/resources) Ihres jar Ihre Datei hinzu (wir gehen davon aus, dass Sie eine xml-Datei mit dem Namenimports.xml) hinzugefügt haben. Anschließend injizieren Sie ResourceLoader, wenn Sie spring verwenden wie brüllen 

@Autowired
private ResourceLoader resourceLoader;

schreiben Sie den folgenden Code, um die Datei zu laden:

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

//Method Body


InputStream invalidCharacterInputStream = URLClassLoader.getSystemResourceAsStream(FILE_LOCATION);

Dies vongetSystemResourceAsStreamzu erhalten, ist die beste Option. Durch das Abrufen des Inputstreams anstelle der Datei oder der URL wird in einer JAR-Datei und als eigenständiger Server gearbeitet.

1
Shano

Es kann etwas spät sein, aber Sie können meine Bibliothek KResourceLoader verwenden, um eine Ressource aus Ihrem Glas zu erhalten:

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

Der folgende Pfad hat für mich funktioniert: classpath:/path/to/resource/in/jar

1
Anatoly

Dies ist, so wurde gesagt, nicht die optimale Methode zum Laden von Ressourcen. Wenn Sie jedoch unbedingt einen Java.io.File-Verweis haben müssen, versuchen Sie Folgendes:

 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
  }

Dadurch erhalten Sie einen Java.net.URL und können in einem Java.io.File-Konstruktor verwendet werden.

1
Jes

In einer JAR-Datei befindet sich die Ressource absolut in der Pakethierarchie (nicht in der Dateisystemhierarchie). Wenn Sie also über die Klasse com.example.Sweet eine Ressource namens "./default.conf" laden, wird der Name der Ressource als "/com/example/default.conf" angegeben. 

Aber wenn es in einem Glas ist, dann ist es keine Datei ...

0
Vilnis Krumins

Vielleicht kann diese Methode für eine schnelle Lösung verwendet werden.

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