Mã của tôi chạy bên trong tệp JAR, giả sử foo.jar và tôi cần biết, trong mã, trong thư mục nào đang chạy foo.jar .
Vì vậy, nếu foo.jar ở trong C:\FOO\
, tôi muốn có được đường dẫn đó bất kể thư mục làm việc hiện tại của tôi là gì.
Mã của tôi chạy bên trong tệp JAR, giả sử foo.jar và tôi cần biết, trong mã, trong thư mục nào đang chạy foo.jar .
Vì vậy, nếu foo.jar ở trong C:\FOO\
, tôi muốn có được đường dẫn đó bất kể thư mục làm việc hiện tại của tôi là gì.
Câu trả lời:
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
.toURI()).getPath();
Thay thế "MyClass" bằng tên của lớp bạn.
Rõ ràng, điều này sẽ làm những điều kỳ lạ nếu lớp của bạn được tải từ một vị trí không phải là tệp.
toURI()
bước quan trọng đến các vấn đề tránh với ký tự đặc biệt, bao gồm cả dấu và dấu cộng. Một lớp lót chính xác là: return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI());
Sử dụng URLDecoder
không hoạt động đối với nhiều ký tự đặc biệt. Xem câu trả lời của tôi dưới đây để biết thêm chi tiết.
getProtectionDomain
là null nếu bạn nhận được lớp của mình từ một chiến lược:val strace = Thread.currentThread().getStackTrace; val path = strace(1).getClass.getProtectionDomain
Giải pháp tốt nhất cho tôi:
String path = Test.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");
Điều này sẽ giải quyết vấn đề với không gian và các ký tự đặc biệt.
URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
) trên Linux. Tuy nhiên, tôi đã không thử trên Windows.
URLDecoder
để giải mã các ký tự đặc biệt. Cụ thể, các ký tự như +
sẽ bị giải mã sai thành khoảng trắng. Xem câu trả lời của tôi để biết chi tiết.
Để có được File
một cái cho trước Class
, có hai bước:
Class
thành mộtURL
URL
thành mộtFile
Điều quan trọng là phải hiểu cả hai bước, và không giới thiệu chúng.
Một khi bạn có File
, bạn có thể gọigetParentFile
để lấy thư mục chứa, nếu đó là thứ bạn cần.
Class
đếnURL
Như đã thảo luận trong các câu trả lời khác, có hai cách chính để tìm một URL
liên quan đến a Class
.
URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();
URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");
Cả hai đều có ưu và nhược điểm.
Cách getProtectionDomain
tiếp cận mang lại vị trí cơ sở của lớp (ví dụ: tệp JAR chứa). Tuy nhiên, có thể chính sách bảo mật của thời gian chạy Java sẽ xuất hiện SecurityException
khi gọi getProtectionDomain()
, vì vậy nếu ứng dụng của bạn cần chạy trong nhiều môi trường khác nhau, tốt nhất nên thử nghiệm tất cả chúng.
Cách getResource
tiếp cận mang lại đường dẫn tài nguyên URL đầy đủ của lớp, từ đó bạn sẽ cần thực hiện thao tác chuỗi bổ sung. Nó có thể là một file:
đường dẫn, nhưng nó cũng có thể jar:file:
hoặc thậm chí là một thứ gì đó khó chịu hơn bundleresource://346.fwk2106232034:4/foo/Bar.class
khi thực thi trong khung OSGi. Ngược lại, getProtectionDomain
cách tiếp cận chính xác mang lại mộtfile:
URL ngay cả trong OSGi.
Lưu ý rằng cả hai getResource("")
và getResource(".")
đều thất bại trong các thử nghiệm của tôi, khi lớp nằm trong tệp JAR; cả hai lời mời đều trả về null. Vì vậy, tôi đề nghị cách gọi số 2 được hiển thị ở trên, vì nó có vẻ an toàn hơn.
URL
đếnFile
Dù bằng cách nào, một khi bạn có a URL
, bước tiếp theo là chuyển đổi thành a File
. Đây là thách thức riêng của nó; xem bài đăng trên blog của Kohsuke Kawaguchi về nó để biết chi tiết đầy đủ, nhưng tóm lại, bạn có thể sử dụngnew File(url.toURI())
miễn là URL hoàn toàn được định dạng.
Cuối cùng, tôi rất không khuyến khích sử dụng URLDecoder
. Một số ký tự của URL :
và /
đặc biệt là các ký tự được mã hóa URL hợp lệ. Từ Javadoc URLDecoder :
Giả định rằng tất cả các ký tự trong chuỗi được mã hóa là một trong những điều sau đây: "a" đến "z", "A" đến "Z", "0" đến "9" và "-", "_", " . "và" * ". Ký tự "%" được cho phép nhưng được hiểu là bắt đầu một chuỗi thoát đặc biệt.
...
Có hai cách có thể trong đó bộ giải mã này có thể xử lý các chuỗi bất hợp pháp. Nó có thể để các nhân vật bất hợp pháp một mình hoặc nó có thể ném IllegalArgumentException. Cách tiếp cận nào bộ giải mã được để lại cho việc thực hiện.
Trong thực tế, URLDecoder
nói chung không ném IllegalArgumentException
như bị đe dọa ở trên. Và nếu đường dẫn tệp của bạn có không gian được mã hóa dưới dạng %20
, phương pháp này có thể hoạt động. Tuy nhiên, nếu đường dẫn tệp của bạn có các ký tự không phải là chữ và số khác, chẳng hạn như +
bạn sẽ gặp vấn đề với việc URLDecoder
xáo trộn đường dẫn tệp của mình.
Để đạt được các bước này, bạn có thể có các phương pháp như sau:
/**
* 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);
}
Bạn có thể tìm thấy các phương thức này trong thư viện chung SciJava :
Bạn cũng có thể dùng:
CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
String jarDir = jarFile.getParentFile().getPath();
Sử dụng ClassLoader.getResource () để tìm URL cho lớp hiện tại của bạn.
Ví dụ:
package foo;
public class Test
{
public static void main(String[] args)
{
ClassLoader loader = Test.class.getClassLoader();
System.out.println(loader.getResource("foo/Test.class"));
}
}
(Ví dụ này được lấy từ một câu hỏi tương tự .)
Để tìm thư mục, sau đó bạn cần tách URL theo cách thủ công. Xem hướng dẫn JarClassLoader để biết định dạng của URL jar.
NPE
vì bạn đã không trả lời cho câu hỏi đã được hỏi (đường dẫn đến thư mục JAR đã được hỏi và bạn đã trả lời câu hỏi hoàn toàn khác: đường đến lớp). 2. Như được chỉ ra bởi những người khác, và tôi đã có cùng một vấn đề, nó không hoạt động cho các applet. 3. Đường dẫn trả về hoàn toàn không phải là biểu diễn đường dẫn chính tắc : jar:file:/listener/build/libs/listener-1.0.0-all.jar!/shared/Test.class
.
Tôi ngạc nhiên khi thấy rằng gần đây không có đề xuất sử dụng Path
. Ở đây sau một trích dẫn: " Các Path
lớp bao gồm các phương pháp khác nhau có thể được sử dụng để có được thông tin về đường dẫn, các yếu tố tiếp cận của con đường, chuyển đổi các đường dẫn đến các hình thức khác, hoặc các phần chiết xuất của một con đường "
Vì vậy, một lựa chọn tốt là nhận được sự Path
phản đối như:
Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());
Giải pháp duy nhất phù hợp với tôi trên Linux, Mac và Windows:
public static String getJarContainingFolder(Class aclass) throws Exception {
CodeSource codeSource = aclass.getProtectionDomain().getCodeSource();
File jarFile;
if (codeSource.getLocation() != null) {
jarFile = new File(codeSource.getLocation().toURI());
}
else {
String path = aclass.getResource(aclass.getSimpleName() + ".class").getPath();
String jarFilePath = path.substring(path.indexOf(":") + 1, path.indexOf("!"));
jarFilePath = URLDecoder.decode(jarFilePath, "UTF-8");
jarFile = new File(jarFilePath);
}
return jarFile.getParentFile().getAbsolutePath();
}
Tôi đã có cùng một vấn đề và tôi đã giải quyết nó theo cách đó:
File currentJavaJarFile = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String currentJavaJarFilePath = currentJavaJarFile.getAbsolutePath();
String currentRootDirectoryPath = currentJavaJarFilePath.replace(currentJavaJarFile.getName(), "");
Tôi hy vọng tôi đã giúp bạn.
Đây là bản nâng cấp cho các bình luận khác, dường như tôi chưa hoàn thiện về các chi tiết cụ thể của
sử dụng "thư mục" tương đối bên ngoài tệp .jar (trong cùng vị trí của jar):
String path =
YourMainClassName.class.getProtectionDomain().
getCodeSource().getLocation().getPath();
path =
URLDecoder.decode(
path,
"UTF-8");
BufferedImage img =
ImageIO.read(
new File((
new File(path).getParentFile().getPath()) +
File.separator +
"folder" +
File.separator +
"yourfile.jpg"));
URLDecoder
để giải mã các ký tự đặc biệt. Cụ thể, các ký tự như +
sẽ bị giải mã sai thành khoảng trắng. Xem câu trả lời của tôi để biết chi tiết.
URLDecoder
, mặc dù tên của nó, là để giải mã URL và hình thức tên và giá trị tham số, không phải URL.
Để có được đường dẫn chạy tệp jar, tôi đã nghiên cứu các giải pháp trên và thử tất cả các phương thức tồn tại một số khác biệt. Nếu các mã này đang chạy trong IDE Eclipse, tất cả chúng sẽ có thể tìm thấy đường dẫn của tệp bao gồm lớp được chỉ định và mở hoặc tạo một tệp được chỉ định với đường dẫn tìm thấy.
Nhưng thật khó khăn, khi chạy tệp jar có thể chạy trực tiếp hoặc thông qua dòng lệnh, nó sẽ thất bại vì đường dẫn của tệp jar nhận được từ các phương thức trên sẽ đưa ra một đường dẫn nội bộ trong tệp jar, đó là luôn luôn cung cấp một đường dẫn như
rsrc: tên dự án (có lẽ tôi nên nói rằng đó là tên gói của tệp lớp chính - lớp được chỉ định)
Tôi không thể chuyển đổi đường dẫn rsrc: ... thành đường dẫn bên ngoài, đó là khi chạy tệp jar bên ngoài IDE Eclipse, nó không thể lấy đường dẫn của tệp jar.
Cách khả thi duy nhất để có được đường dẫn chạy tệp jar bên ngoài IDE Eclipse là
System.getProperty("java.class.path")
dòng mã này có thể trả về đường dẫn sống (bao gồm tên tệp) của tệp jar đang chạy (lưu ý rằng đường dẫn trả lại không phải là thư mục làm việc), vì tài liệu java và một số người nói rằng nó sẽ trả về đường dẫn của tất cả các tệp lớp trong cùng một thư mục, nhưng như các thử nghiệm của tôi nếu trong cùng một thư mục bao gồm nhiều tệp jar, nó chỉ trả về đường dẫn chạy jar (về vấn đề nhiều đường dẫn thực sự đã xảy ra trong Eclipse).
java.class.path
có thể được đa trị hóa. Một trong những giá trị đó chắc chắn sẽ cung cấp thư mục hoặc tệp JAR nơi lớp hiện tại được đặt, nhưng cái nào?
Các câu trả lời khác dường như trỏ đến nguồn mã là vị trí tệp Jar không phải là thư mục.
Sử dụng
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();
câu trả lời được chọn ở trên không hoạt động nếu bạn chạy jar của mình bằng cách nhấp vào nó từ môi trường máy tính để bàn Gnome (không phải từ bất kỳ tập lệnh hoặc thiết bị đầu cuối nào).
Thay vào đó, tôi thích rằng giải pháp sau đây đang hoạt động ở mọi nơi:
try {
return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
return "";
}
URLDecoder
để giải mã các ký tự đặc biệt. Cụ thể, các ký tự như +
sẽ bị giải mã sai thành khoảng trắng. Xem câu trả lời của tôi để biết chi tiết.
NullPointerException
NPE
nếu không có tài nguyên trong JAR.
Trên thực tế đây là một phiên bản tốt hơn - phiên bản cũ đã thất bại nếu tên thư mục có khoảng trắng trong đó.
private String getJarFolder() {
// get name and path
String name = getClass().getName().replace('.', '/');
name = getClass().getResource("/" + name + ".class").toString();
// remove junk
name = name.substring(0, name.indexOf(".jar"));
name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' ');
// remove escape characters
String s = "";
for (int k=0; k<name.length(); k++) {
s += name.charAt(k);
if (name.charAt(k) == ' ') k += 2;
}
// replace '/' with system separator char
return s.replace('/', File.separatorChar);
}
Đối với thất bại với các applet, bạn thường sẽ không có quyền truy cập vào các tệp cục bộ. Tôi không biết nhiều về JWS nhưng để xử lý các tệp cục bộ thì có thể không tải được ứng dụng.?
Tôi đã cố gắng để có được đường chạy jar bằng cách sử dụng
String folder = MyClassName.class.getProtectionDomain().getCodeSource().getLocation().getPath();
c: \ app> java -jar application.jar
Chạy ứng dụng jar có tên "application.jar", trên Windows trong thư mục " c: \ app ", giá trị của biến String "thư mục" là " \ c: \ app \ application.jar " và tôi gặp vấn đề khi kiểm tra sự đúng đắn của con đường
File test = new File(folder);
if(file.isDirectory() && file.canRead()) { //always false }
Vì vậy, tôi đã cố gắng định nghĩa "kiểm tra" là:
String fold= new File(folder).getParentFile().getPath()
File test = new File(fold);
để có được đường dẫn ở định dạng đúng như " c: \ app " thay vì " \ c: \ app \ application.jar " và tôi nhận thấy rằng nó hoạt động.
Giải pháp đơn giản nhất là vượt qua đường dẫn làm đối số khi chạy jar.
Bạn có thể tự động hóa điều này với một tập lệnh shell (.bat trong Windows, .sh ở bất kỳ nơi nào khác):
java -jar my-jar.jar .
Tôi đã sử dụng .
để vượt qua thư mục làm việc hiện tại.
CẬP NHẬT
Bạn có thể muốn dán tệp jar trong thư mục con để người dùng không vô tình nhấp vào tệp. Mã của bạn cũng nên kiểm tra để đảm bảo rằng các đối số dòng lệnh đã được cung cấp và cung cấp một thông báo lỗi tốt nếu các đối số bị thiếu.
Tôi đã phải loay hoay rất nhiều trước khi cuối cùng tôi tìm thấy một giải pháp hiệu quả (và ngắn).
Có thể là jarLocation
đi kèm với một tiền tố như file:\
hoặc jar:file\
, có thể được loại bỏ bằng cách sử dụng String#substring()
.
URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();
String path = getClass().getResource("").getPath();
Đường dẫn luôn đề cập đến tài nguyên trong tệp jar.
String path = new File(getClass().getResource("").getPath()).getParentFile().getParent(); File jarDir = new File(path.substring(5));
getResource("")
và đều getResource(".")
thất bại trong các bài kiểm tra của tôi, khi lớp nằm trong tệp JAR; cả hai lời mời đều trả về null.
NullPointerException
.
public static String dir() throws URISyntaxException
{
URI path=Main.class.getProtectionDomain().getCodeSource().getLocation().toURI();
String name= Main.class.getPackage().getName()+".jar";
String path2 = path.getRawPath();
path2=path2.substring(1);
if (path2.contains(".jar"))
{
path2=path2.replace(name, "");
}
return path2;}
Hoạt động tốt trên Windows
Một điều gây nản lòng là khi bạn đang phát triển trong Eclipse MyClass.class.getProtectionDomain().getCodeSource().getLocation()
trả về /bin
thư mục rất tuyệt, nhưng khi bạn biên dịch nó vào một tệp jar, đường dẫn bao gồm /myjarname.jar
phần cung cấp cho bạn tên tệp bất hợp pháp.
Để có mã hoạt động cả trong ide và một khi nó được biên dịch vào một jar, tôi sử dụng đoạn mã sau:
URL applicationRootPathURL = getClass().getProtectionDomain().getCodeSource().getLocation();
File applicationRootPath = new File(applicationRootPathURL.getPath());
File myFile;
if(applicationRootPath.isDirectory()){
myFile = new File(applicationRootPath, "filename");
}
else{
myFile = new File(applicationRootPath.getParentFile(), "filename");
}
Không thực sự chắc chắn về những người khác nhưng trong trường hợp của tôi, nó không hoạt động với "Bình có thể chạy được" và tôi đã làm cho nó hoạt động bằng cách sửa mã cùng nhau từ câu trả lời phchen2 và một liên kết khác từ liên kết này: Làm thế nào để có được đường dẫn của tệp JAR đang chạy? Mật mã:
String path=new java.io.File(Server.class.getProtectionDomain()
.getCodeSource()
.getLocation()
.getPath())
.getAbsolutePath();
path=path.substring(0, path.lastIndexOf("."));
path=path+System.getProperty("java.class.path");
Đã thử một vài giải pháp trên đó nhưng không có kết quả chính xác nào cho trường hợp (có lẽ đặc biệt) rằng bình có thể chạy được đã được xuất với "Đóng gói thư viện bên ngoài" trong Eclipse. Vì một số lý do, tất cả các giải pháp dựa trên ProtectionDomain đều không có kết quả trong trường hợp đó.
Từ việc kết hợp một số giải pháp ở trên, tôi đã quản lý để đạt được mã làm việc sau:
String surroundingJar = null;
// gets the path to the jar file if it exists; or the "bin" directory if calling from Eclipse
String jarDir = new File(ClassLoader.getSystemClassLoader().getResource(".").getPath()).getAbsolutePath();
// gets the "bin" directory if calling from eclipse or the name of the .jar file alone (without its path)
String jarFileFromSys = System.getProperty("java.class.path").split(";")[0];
// If both are equal that means it is running from an IDE like Eclipse
if (jarFileFromSys.equals(jarDir))
{
System.out.println("RUNNING FROM IDE!");
// The path to the jar is the "bin" directory in that case because there is no actual .jar file.
surroundingJar = jarDir;
}
else
{
// Combining the path and the name of the .jar file to achieve the final result
surroundingJar = jarDir + jarFileFromSys.substring(1);
}
System.out.println("JAR File: " + surroundingJar);
Phương thức này, được gọi từ mã trong kho lưu trữ, trả về thư mục chứa tệp .jar. Nó nên hoạt động trong cả Windows hoặc Unix.
private String getJarFolder() {
String name = this.getClass().getName().replace('.', '/');
String s = this.getClass().getResource("/" + name + ".class").toString();
s = s.replace('/', File.separatorChar);
s = s.substring(0, s.indexOf(".jar")+4);
s = s.substring(s.lastIndexOf(':')-1);
return s.substring(0, s.lastIndexOf(File.separatorChar)+1);
}
Xuất phát từ mã tại: Xác định nếu chạy từ JAR
Đề cập rằng nó chỉ được kiểm tra Windows
nhưng tôi nghĩ nó hoạt động hoàn hảo trên các Hệ điều hành khác [ Linux,MacOs,Solaris
] :).
Tôi đã có 2 .jar
tập tin trong cùng một thư mục. Tôi muốn từ một .jar
tệp để bắt đầu .jar
tệp khác trong cùng thư mục.
Vấn đề là khi bạn khởi động nó từ cmd
thư mục hiện tại system32
.
Cảnh báo!
;][[;'57f2g34g87-8+9-09!2#@!$%^^&()
hoặc()%&$%^@#
nó hoạt động tốt.ProcessBuilder
với dưới đây như sau:🍂 ..
//The class from which i called this was the class `Main`
String path = getBasePathForClass(Main.class);
String applicationPath= new File(path + "application.jar").getAbsolutePath();
System.out.println("Directory Path is : "+applicationPath);
//Your know try catch here
//Mention that sometimes it doesn't work for example with folder `;][[;'57f2g34g87-8+9-09!2#@!$%^^&()`
ProcessBuilder builder = new ProcessBuilder("java", "-jar", applicationPath);
builder.redirectErrorStream(true);
Process process = builder.start();
//...code
🍂 getBasePathForClass(Class<?> classs)
:
/**
* Returns the absolute path of the current directory in which the given
* class
* file is.
*
* @param classs
* @return The absolute path of the current directory in which the class
* file is.
* @author GOXR3PLUS[StackOverFlow user] + bachden [StackOverFlow user]
*/
public static final String getBasePathForClass(Class<?> classs) {
// Local variables
File file;
String basePath = "";
boolean failed = false;
// Let's give a first try
try {
file = new File(classs.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
if (file.isFile() || file.getPath().endsWith(".jar") || file.getPath().endsWith(".zip")) {
basePath = file.getParent();
} else {
basePath = file.getPath();
}
} catch (URISyntaxException ex) {
failed = true;
Logger.getLogger(classs.getName()).log(Level.WARNING,
"Cannot firgue out base path for class with way (1): ", ex);
}
// The above failed?
if (failed) {
try {
file = new File(classs.getClassLoader().getResource("").toURI().getPath());
basePath = file.getAbsolutePath();
// the below is for testing purposes...
// starts with File.separator?
// String l = local.replaceFirst("[" + File.separator +
// "/\\\\]", "")
} catch (URISyntaxException ex) {
Logger.getLogger(classs.getName()).log(Level.WARNING,
"Cannot firgue out base path for class with way (2): ", ex);
}
}
// fix to run inside eclipse
if (basePath.endsWith(File.separator + "lib") || basePath.endsWith(File.separator + "bin")
|| basePath.endsWith("bin" + File.separator) || basePath.endsWith("lib" + File.separator)) {
basePath = basePath.substring(0, basePath.length() - 4);
}
// fix to run inside netbeans
if (basePath.endsWith(File.separator + "build" + File.separator + "classes")) {
basePath = basePath.substring(0, basePath.length() - 14);
}
// end fix
if (!basePath.endsWith(File.separator)) {
basePath = basePath + File.separator;
}
return basePath;
}
Mã này làm việc cho tôi:
private static String getJarPath() throws IOException, URISyntaxException {
File f = new File(LicensingApp.class.getProtectionDomain().().getLocation().toURI());
String jarPath = f.getCanonicalPath().toString();
String jarDir = jarPath.substring( 0, jarPath.lastIndexOf( File.separator ));
return jarDir;
}
Mã này làm việc cho tôi để xác định xem chương trình đang được thực thi trong tệp JAR hay IDE:
private static boolean isRunningOverJar() {
try {
String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();
if (pathJar.toLowerCase().contains(".jar")) {
return true;
} else {
return false;
}
} catch (Exception e) {
return false;
}
}
Nếu tôi cần lấy đường dẫn Windows đầy đủ của tệp JAR, tôi đang sử dụng phương pháp này:
private static String getPathJar() {
try {
final URI jarUriPath =
Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
String jarStringPath = jarUriPath.toString().replace("jar:", "");
String jarCleanPath = Paths.get(new URI(jarStringPath)).toString();
if (jarCleanPath.toLowerCase().contains(".jar")) {
return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
} else {
return null;
}
} catch (Exception e) {
log.error("Error getting JAR path.", e);
return null;
}
}
Mã hoàn chỉnh của tôi hoạt động với ứng dụng Spring Boot bằng cách sử dụng CommandLineRunner
triển khai, để đảm bảo rằng ứng dụng luôn được thực thi trong chế độ xem bảng điều khiển (Nhấp đúp do nhầm lẫn trong tên tệp JAR), tôi đang sử dụng mã tiếp theo:
@SpringBootApplication
public class Application implements CommandLineRunner {
public static void main(String[] args) throws IOException {
Console console = System.console();
if (console == null && !GraphicsEnvironment.isHeadless() && isRunningOverJar()) {
Runtime.getRuntime().exec(new String[]{"cmd", "/c", "start", "cmd", "/k",
"java -jar \"" + getPathJar() + "\""});
} else {
SpringApplication.run(Application.class, args);
}
}
@Override
public void run(String... args) {
/*
Additional code here...
*/
}
private static boolean isRunningOverJar() {
try {
String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();
if (pathJar.toLowerCase().contains(".jar")) {
return true;
} else {
return false;
}
} catch (Exception e) {
return false;
}
}
private static String getPathJar() {
try {
final URI jarUriPath =
Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
String jarStringPath = jarUriPath.toString().replace("jar:", "");
String jarCleanPath = Paths.get(new URI(jarStringPath)).toString();
if (jarCleanPath.toLowerCase().contains(".jar")) {
return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
} else {
return null;
}
} catch (Exception e) {
return null;
}
}
}
Tôi viết bằng Java 7 và thử nghiệm trong Windows 7 với thời gian chạy của Oracle và Ubuntu với thời gian chạy nguồn mở. Điều này hoạt động hoàn hảo cho các hệ thống:
Đường dẫn cho thư mục mẹ của bất kỳ tệp jar đang chạy nào (giả sử lớp gọi mã này là con trực tiếp của chính tệp lưu trữ jar):
try {
fooDir = new File(this.getClass().getClassLoader().getResource("").toURI());
} catch (URISyntaxException e) {
//may be sloppy, but don't really need anything here
}
fooDirPath = fooDir.toString(); // converts abstract (absolute) path to a String
Vì vậy, đường dẫn của foo.jar sẽ là:
fooPath = fooDirPath + File.separator + "foo.jar";
Một lần nữa, điều này không được thử nghiệm trên bất kỳ máy Mac hoặc Windows cũ hơn
Cách getProtectionDomain
tiếp cận đôi khi có thể không hoạt động, ví dụ như khi bạn phải tìm jar cho một số lớp java cốt lõi (ví dụ: trong StringBuilder
lớp trường hợp của tôi trong IBM JDK), tuy nhiên sau đây hoạt động trơn tru:
public static void main(String[] args) {
System.out.println(findSource(MyClass.class));
// OR
System.out.println(findSource(String.class));
}
public static String findSource(Class<?> clazz) {
String resourceToSearch = '/' + clazz.getName().replace(".", "/") + ".class";
java.net.URL location = clazz.getResource(resourceToSearch);
String sourcePath = location.getPath();
// Optional, Remove junk
return sourcePath.replace("file:", "").replace("!" + resourceToSearch, "");
}
Tôi có một cách khác để có được vị trí Chuỗi của một lớp.
URL path = Thread.currentThread().getContextClassLoader().getResource("");
Path p = Paths.get(path.toURI());
String location = p.toString();
Chuỗi đầu ra sẽ có dạng
C:\Users\Administrator\new Workspace\...
Các không gian và các ký tự khác được xử lý, và ở dạng không có file:/
. Vì vậy sẽ dễ sử dụng hơn.