Um das File
für eine bestimmte zu erhalten Class
, gibt es zwei Schritte:
- Konvertieren Sie die
Class
in aURL
- Konvertieren Sie die
URL
in aFile
Es ist wichtig, beide Schritte zu verstehen und nicht zusammenzuführen.
Sobald Sie die haben File
, können Sie anrufengetParentFile
, um den enthaltenen Ordner zu erhalten, wenn Sie dies benötigen.
Schritt 1: Class
bisURL
Wie in anderen Antworten erläutert, gibt es zwei Hauptmethoden, um eine URL
für a relevante zu finden Class
.
URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();
URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");
Beide haben Vor- und Nachteile.
Der getProtectionDomain
Ansatz liefert den Basisort der Klasse (z. B. die enthaltende JAR-Datei). Es ist jedoch möglich, dass die Sicherheitsrichtlinie der Java-Laufzeit SecurityException
beim Aufrufen getProtectionDomain()
ausgelöst wird. Wenn Ihre Anwendung in einer Vielzahl von Umgebungen ausgeführt werden muss, ist es am besten, sie in allen Umgebungen zu testen.
Der getResource
Ansatz liefert den vollständigen URL-Ressourcenpfad der Klasse, von dem aus Sie zusätzliche Zeichenfolgenmanipulationen durchführen müssen. Es kann ein file:
Pfad sein, aber es kann auch jar:file:
oder sogar etwas Unangenehmeres sein, bundleresource://346.fwk2106232034:4/foo/Bar.class
wenn es innerhalb eines OSGi-Frameworks ausgeführt wird. Umgekehrt getProtectionDomain
ergibt der Ansatz korrekt afile:
auch innerhalb von OSGi URL.
Beachten Sie, dass beide getResource("")
und getResource(".")
in meinen Tests fehlgeschlagen sind, als sich die Klasse in einer JAR-Datei befand. Beide Aufrufe gaben null zurück. Daher empfehle ich stattdessen den oben gezeigten Aufruf Nr. 2, da er sicherer erscheint.
Schritt 2: URL
bisFile
In beiden Fällen ist URL
der nächste Schritt , sobald Sie eine haben , die Konvertierung in a File
. Dies ist seine eigene Herausforderung; siehe Kohsuke Kawaguchi Blog - Post über sie für weitere Informationen, aber kurz gesagt, können Sienew File(url.toURI())
, solange die URL vollständig wohlgeformt ist .
Schließlich möchte ich sehr entmutigen verwenden URLDecoder
. Einige Zeichen der URL :
und /
insbesondere sind keine gültigen URL-codierten Zeichen. Aus dem URLDecoder Javadoc:
Es wird angenommen, dass alle Zeichen in der codierten Zeichenfolge eines der folgenden sind: "a" bis "z", "A" bis "Z", "0" bis "9" und "-", "_", " .", und "*". Das Zeichen "%" ist zulässig, wird jedoch als Beginn einer speziellen Escape-Sequenz interpretiert.
...
Es gibt zwei Möglichkeiten, wie dieser Decoder mit illegalen Zeichenfolgen umgehen kann. Es könnte entweder illegale Zeichen in Ruhe lassen oder eine IllegalArgumentException auslösen. Welchen Ansatz der Decoder verfolgt, bleibt der Implementierung überlassen.
In der Praxis wird im URLDecoder
Allgemeinen nicht IllegalArgumentException
wie oben bedroht geworfen . Wenn in Ihrem Dateipfad Leerzeichen codiert sind %20
, scheint dieser Ansatz zu funktionieren. Wenn Ihr Dateipfad jedoch andere nicht alphabetische Zeichen enthält, wie z. B. +
Probleme beim URLDecoder
Verwischen Ihres Dateipfads.
Arbeitscode
Um diese Schritte auszuführen, haben Sie möglicherweise folgende Methoden:
/**
* Gets the base location of the given class.
* <p>
* If the class is directly on the file system (e.g.,
* "/path/to/my/package/MyClass.class") then it will return the base directory
* (e.g., "file:/path/to").
* </p>
* <p>
* If the class is within a JAR file (e.g.,
* "/path/to/my-jar.jar!/my/package/MyClass.class") then it will return the
* path to the JAR (e.g., "file:/path/to/my-jar.jar").
* </p>
*
* @param c The class whose location is desired.
* @see FileUtils#urlToFile(URL) to convert the result to a {@link File}.
*/
public static URL getLocation(final Class<?> c) {
if (c == null) return null; // could not load the class
// try the easy way first
try {
final URL codeSourceLocation =
c.getProtectionDomain().getCodeSource().getLocation();
if (codeSourceLocation != null) return codeSourceLocation;
}
catch (final SecurityException e) {
// NB: Cannot access protection domain.
}
catch (final NullPointerException e) {
// NB: Protection domain or code source is null.
}
// NB: The easy way failed, so we try the hard way. We ask for the class
// itself as a resource, then strip the class's path from the URL string,
// leaving the base path.
// get the class's raw resource path
final URL classResource = c.getResource(c.getSimpleName() + ".class");
if (classResource == null) return null; // cannot find class resource
final String url = classResource.toString();
final String suffix = c.getCanonicalName().replace('.', '/') + ".class";
if (!url.endsWith(suffix)) return null; // weird URL
// strip the class's path from the URL string
final String base = url.substring(0, url.length() - suffix.length());
String path = base;
// remove the "jar:" prefix and "!/" suffix, if present
if (path.startsWith("jar:")) path = path.substring(4, path.length() - 2);
try {
return new URL(path);
}
catch (final MalformedURLException e) {
e.printStackTrace();
return null;
}
}
/**
* Converts the given {@link URL} to its corresponding {@link File}.
* <p>
* This method is similar to calling {@code new File(url.toURI())} except that
* it also handles "jar:file:" URLs, returning the path to the JAR file.
* </p>
*
* @param url The URL to convert.
* @return A file path suitable for use with e.g. {@link FileInputStream}
* @throws IllegalArgumentException if the URL does not correspond to a file.
*/
public static File urlToFile(final URL url) {
return url == null ? null : urlToFile(url.toString());
}
/**
* Converts the given URL string to its corresponding {@link File}.
*
* @param url The URL to convert.
* @return A file path suitable for use with e.g. {@link FileInputStream}
* @throws IllegalArgumentException if the URL does not correspond to a file.
*/
public static File urlToFile(final String url) {
String path = url;
if (path.startsWith("jar:")) {
// remove "jar:" prefix and "!/" suffix
final int index = path.indexOf("!/");
path = path.substring(4, index);
}
try {
if (PlatformUtils.isWindows() && path.matches("file:[A-Za-z]:.*")) {
path = "file:/" + path.substring(5);
}
return new File(new URL(path).toURI());
}
catch (final MalformedURLException e) {
// NB: URL is not completely well-formed.
}
catch (final URISyntaxException e) {
// NB: URL is not completely well-formed.
}
if (path.startsWith("file:")) {
// pass through the URL as-is, minus "file:" prefix
path = path.substring(5);
return new File(path);
}
throw new IllegalArgumentException("Invalid URL: " + url);
}
Sie finden diese Methoden in der SciJava Common- Bibliothek: