Untuk mendapatkan Fileuntuk diberikan Class, ada dua langkah:
- Konversi
Classke aURL
- Konversi
URLke aFile
Penting untuk memahami kedua langkah, dan tidak mengacaukannya.
Setelah Anda memiliki File, Anda dapat menelepon getParentFileuntuk mendapatkan folder yang berisi, jika itu yang Anda butuhkan.
Langkah 1: ClasskeURL
Seperti dibahas dalam jawaban lain, ada dua cara utama untuk menemukan yang URLrelevan dengan a Class.
URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();
URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");
Keduanya memiliki pro dan kontra.
The getProtectionDomainPendekatan menghasilkan lokasi dasar kelas (misalnya, berisi file JAR). Namun, ada kemungkinan bahwa kebijakan keamanan Java runtime akan dilemparkan SecurityExceptionsaat memanggil getProtectionDomain(), jadi jika aplikasi Anda perlu dijalankan di berbagai lingkungan, yang terbaik adalah mengujinya di semua lingkungan tersebut.
The getResourcePendekatan menghasilkan path sumber daya URL lengkap dari kelas, dari mana Anda akan perlu melakukan tambahan manipulasi string. Ini mungkin file:jalan, tetapi juga bisa jar:file:atau bahkan sesuatu yang lebih buruk seperti bundleresource://346.fwk2106232034:4/foo/Bar.classketika mengeksekusi dalam kerangka OSGi. Sebaliknya, getProtectionDomainpendekatan menghasilkan file:URL dengan benar bahkan dari dalam OSGi.
Perhatikan bahwa keduanya getResource("")dan getResource(".")gagal dalam pengujian saya, ketika kelas berada dalam file JAR; kedua doa dikembalikan nol. Jadi saya merekomendasikan doa # 2 yang ditunjukkan di atas sebagai gantinya, karena tampaknya lebih aman.
Langkah 2: URLkeFile
Either way, setelah Anda memiliki URL, langkah selanjutnya adalah mengonversi ke a File. Ini adalah tantangannya sendiri; lihat posting blog Kohsuke Kawaguchi tentang hal itu untuk detail lengkap, tetapi singkatnya, Anda dapat menggunakan new File(url.toURI())selama URL benar-benar terbentuk dengan baik.
Terakhir, saya akan sangat tidak suka menggunakan URLDecoder. Beberapa karakter URL, :dan /khususnya, bukan karakter yang disandikan dengan URL. Dari URLDecoder Javadoc:
Diasumsikan bahwa semua karakter dalam string yang disandikan adalah salah satu dari yang berikut: "a" hingga "z", "A" hingga "Z", "0" hingga "9", dan "-", "_", " . ", dan" * ". Karakter "%" diperbolehkan tetapi ditafsirkan sebagai awal dari urutan lolos khusus.
...
Ada dua cara yang memungkinkan dekoder ini dapat menangani string ilegal. Itu bisa meninggalkan karakter ilegal sendirian atau bisa melempar IllegalArgumentException. Pendekatan mana yang diambil oleh decoder diserahkan pada implementasi.
Dalam praktiknya, URLDecoderumumnya tidak melempar IllegalArgumentExceptionseperti terancam di atas. Dan jika path file Anda memiliki ruang yang disandikan %20, pendekatan ini mungkin berfungsi. Namun, jika jalur file Anda memiliki karakter non-alfamerik lain seperti +Anda akan mengalami masalah dengan URLDecodermengatur jalur file Anda.
Kode kerja
Untuk mencapai langkah-langkah ini, Anda mungkin memiliki metode seperti berikut:
/**
* 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);
}
Anda dapat menemukan metode ini di perpustakaan umum SciJava :