รหัสของฉันทำงานในไฟล์ JAR พูดว่าfoo.jarและฉันจำเป็นต้องรู้ในรหัสว่าโฟลเดอร์ใดที่foo.jarกำลังเรียกใช้อยู่
ดังนั้นถ้าfoo.jarอยู่ในC:\FOO\
ฉันต้องการได้รับเส้นทางนั้นไม่ว่าไดเรกทอรีทำงานปัจจุบันของฉันคืออะไร
รหัสของฉันทำงานในไฟล์ JAR พูดว่าfoo.jarและฉันจำเป็นต้องรู้ในรหัสว่าโฟลเดอร์ใดที่foo.jarกำลังเรียกใช้อยู่
ดังนั้นถ้าfoo.jarอยู่ในC:\FOO\
ฉันต้องการได้รับเส้นทางนั้นไม่ว่าไดเรกทอรีทำงานปัจจุบันของฉันคืออะไร
คำตอบ:
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
.toURI()).getPath();
แทนที่ "MyClass" ด้วยชื่อคลาสของคุณ
เห็นได้ชัดว่าสิ่งนี้จะทำสิ่งแปลกถ้าชั้นของคุณถูกโหลดจากที่ไม่ใช่ไฟล์
toURI()
ขั้นตอนที่มีความสำคัญต่อปัญหาหลีกเลี่ยงการมีตัวอักษรพิเศษรวมถึงช่องว่างและ pluses หนึ่งซับที่ถูกต้องคือ: return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI());
การใช้URLDecoder
ไม่สามารถใช้ได้กับอักขระพิเศษจำนวนมาก ดูคำตอบของฉันด้านล่างสำหรับรายละเอียดเพิ่มเติม
getProtectionDomain
เป็นโมฆะถ้าคุณได้รับชั้นเรียนของคุณจาก stracktrace:val strace = Thread.currentThread().getStackTrace; val path = strace(1).getClass.getProtectionDomain
ทางออกที่ดีที่สุดสำหรับฉัน:
String path = Test.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");
สิ่งนี้ควรแก้ปัญหาช่องว่างและอักขระพิเศษ
URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
) บน Linux อย่างไรก็ตามฉันไม่ได้ลองบน Windows
URLDecoder
ในการถอดรหัสอักขระพิเศษ โดยเฉพาะอย่างยิ่งตัวละครที่ชอบ+
จะถูกถอดรหัสไปยังช่องว่างอย่างผิดพลาด ดูคำตอบของฉันสำหรับรายละเอียด
เพื่อให้ได้รับFile
สำหรับClass
มีสองขั้นตอน:
Class
เป็นURL
URL
เป็นFile
เป็นสิ่งสำคัญที่จะต้องเข้าใจทั้งสองขั้นตอนและไม่ทำให้พวกเขาสับสน
เมื่อคุณมีFile
คุณสามารถโทรgetParentFile
โฟลเดอร์ที่มีหากนั่นคือสิ่งที่คุณต้องการ
Class
ถึงURL
ตามที่กล่าวไว้ในคำตอบอื่น ๆ มีสองวิธีที่สำคัญในการหาที่เกี่ยวข้องกับURL
Class
URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();
URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");
ทั้งสองมีข้อดีและข้อเสีย
getProtectionDomain
วิธีถัวเฉลี่ยที่ตั้งฐานของการเรียน (เช่นไฟล์ JAR มี) อย่างไรก็ตามอาจเป็นไปได้ว่านโยบายความปลอดภัยของ Java runtime จะแสดงขึ้นSecurityException
เมื่อมีการโทรgetProtectionDomain()
ดังนั้นหากแอปพลิเคชันของคุณต้องการทำงานในสภาพแวดล้อมที่หลากหลายจึงเป็นสิ่งที่ดีที่สุดในการทดสอบทั้งหมด
getResource
วิธีถัวเฉลี่ยเส้นทางทรัพยากร URL แบบเต็มของชั้นเรียนซึ่งคุณจะต้องดำเนินการจัดการสตริงเพิ่มเติม อาจเป็นfile:
เส้นทาง แต่ก็อาจเป็นjar:file:
หรือแม้แต่สิ่งที่น่าสนใจกว่าbundleresource://346.fwk2106232034:4/foo/Bar.class
เมื่อดำเนินการภายในกรอบงาน OSGi ในทางกลับกันgetProtectionDomain
วิธีการที่ให้ผลตอบแทนที่ถูกต้องfile:
URL ได้แม้ใน OSGi
โปรดทราบว่าทั้งสองgetResource("")
และgetResource(".")
ล้มเหลวในการทดสอบของฉันเมื่อชั้นอยู่ในไฟล์ JAR; การร้องขอทั้งสองคืนค่า null ดังนั้นฉันขอแนะนำการเรียกใช้ # 2 ที่แสดงด้านบนแทนเนื่องจากดูเหมือนปลอดภัยกว่า
URL
ถึงFile
ทั้งสองวิธีเมื่อคุณมีขั้นตอนต่อไปคือการแปลงไปURL
File
นี่คือความท้าทายของตัวเอง ดูโพสต์บล็อกของ Kohsuke Kawaguchi เกี่ยวกับรายละเอียดแบบเต็ม แต่ในระยะสั้นคุณสามารถใช้new File(url.toURI())
ตราบใดที่ URL มีรูปแบบที่สมบูรณ์
สุดท้ายนี้ผมจะขอกีดกันการURLDecoder
ใช้ อักขระบางตัวของ URL :
และ/
โดยเฉพาะอย่างยิ่งไม่ใช่อักขระที่เข้ารหัส URL จากURLDecoder Javadoc:
สันนิษฐานว่าตัวละครทั้งหมดในสตริงที่เข้ารหัสเป็นหนึ่งในสิ่งต่อไปนี้: "a" ถึง "z", "A" ถึง "Z", "0" ถึง "9" และ "-", "_", " . ", และ" * " อนุญาตให้ใช้อักขระ "%" แต่ถูกตีความว่าเป็นจุดเริ่มต้นของลำดับหลบหนีพิเศษ
...
มีสองวิธีที่เป็นไปได้ในการถอดรหัสนี้สามารถจัดการกับสายอักขระที่ผิดกฎหมาย มันอาจปล่อยให้ตัวละครผิดกฎหมายอยู่คนเดียวหรืออาจโยน IllegalArgumentException วิธีการถอดรหัสที่ใช้จะถูกนำไปใช้งาน
ในทางปฏิบัติURLDecoder
โดยทั่วไปจะไม่โยนIllegalArgumentException
ตามที่ถูกคุกคามข้างต้น และหากเส้นทางไฟล์ของคุณมีการเข้ารหัสเป็นช่องว่าง%20
วิธีการนี้อาจใช้งานได้ อย่างไรก็ตามหากเส้นทางไฟล์ของคุณมีตัวอักษรอื่นที่ไม่ใช่ตัวอักษรเช่น+
คุณจะมีปัญหากับการURLDecoder
จัดการพา ธ ไฟล์ของคุณ
เพื่อให้บรรลุตามขั้นตอนเหล่านี้คุณอาจมีวิธีการดังต่อไปนี้:
/**
* 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);
}
คุณสามารถค้นหาวิธีการเหล่านี้ได้ในห้องสมุดทั่วไปของ SciJava :
คุณยังสามารถใช้:
CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
String jarDir = jarFile.getParentFile().getPath();
ใช้ ClassLoader.getResource () เพื่อค้นหา URL สำหรับคลาสปัจจุบันของคุณ
ตัวอย่างเช่น:
package foo;
public class Test
{
public static void main(String[] args)
{
ClassLoader loader = Test.class.getClassLoader();
System.out.println(loader.getResource("foo/Test.class"));
}
}
(ตัวอย่างนี้นำมาจากคำถามที่คล้ายกัน )
ในการค้นหาไดเรกทอรีคุณจะต้องแยก URL ด้วยตนเอง ดูบทช่วยสอน JarClassLoaderสำหรับรูปแบบ URL ของ jar
NPE
เพราะคุณไม่ได้ตอบคำถามที่ถูกถาม (เส้นทางไปยัง JAR dir ถูกถามและคุณตอบคำถามที่แตกต่างกันอย่างสิ้นเชิง: เส้นทางสู่ชั้นเรียน) 2. ตามที่คนอื่น ๆ ชี้และฉันได้รับปัญหาเดียวกันมันไม่ทำงานสำหรับแอปเพล็ต 3. เส้นทางที่ส่งคืนไม่ใช่การแสดงเส้นทางแบบบัญญัติทั้งหมด: jar:file:/listener/build/libs/listener-1.0.0-all.jar!/shared/Test.class
.
Path
ผมแปลกใจที่จะเห็นใครที่เพิ่งเสนอให้ใช้ นี่ต่อไปนี้อ้างอิง: " ระดับรวมถึงวิธีการต่าง ๆ ที่สามารถนำมาใช้เพื่อให้ได้ข้อมูลเกี่ยวกับเส้นทางการเข้าถึงองค์ประกอบของเส้นทาง, แปลงเส้นทางไปยังรูปแบบอื่น ๆ หรือบางส่วนสารสกัดจากเส้นทาง "Path
ดังนั้นทางเลือกที่ดีคือการได้รับPath
objest เป็น:
Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());
ทางออกเดียวที่เหมาะกับฉันบน Linux, Mac และ 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();
}
ฉันมีปัญหาเดียวกันและฉันแก้ไขมันด้วยวิธีนี้:
File currentJavaJarFile = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String currentJavaJarFilePath = currentJavaJarFile.getAbsolutePath();
String currentRootDirectoryPath = currentJavaJarFilePath.replace(currentJavaJarFile.getName(), "");
ฉันหวังว่าฉันจะช่วยคุณ
นี่คือการอัปเกรดเป็นความคิดเห็นอื่น ๆ ซึ่งดูเหมือนว่าฉันจะไม่สมบูรณ์สำหรับข้อมูลเฉพาะของ
ใช้ "โฟลเดอร์" สัมพัทธ์นอกไฟล์. jar (ในตำแหน่งเดียวกันของ 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
ในการถอดรหัสอักขระพิเศษ โดยเฉพาะอย่างยิ่งตัวละครที่ชอบ+
จะถูกถอดรหัสไปยังช่องว่างอย่างผิดพลาด ดูคำตอบของฉันสำหรับรายละเอียด
URLDecoder
แม้จะมีชื่อเป็นของมันสำหรับการถอดรหัส URL และชื่อพารามิเตอร์และค่าฟอร์มไม่ใช่ URL
เพื่อให้ได้เส้นทางของการรันไฟล์ jar ฉันได้ศึกษาวิธีแก้ไขปัญหาข้างต้นแล้วลองใช้วิธีการทั้งหมดที่มีความแตกต่างกันบ้าง หากรหัสเหล่านี้กำลังทำงานใน Eclipse IDE พวกเขาควรจะสามารถค้นหาพา ธ ของไฟล์รวมถึงคลาสที่ระบุและเปิดหรือสร้างไฟล์ที่ระบุพร้อมกับพา ธ ที่พบ
แต่มันเป็นเรื่องยากเมื่อรันไฟล์ jar ที่รันได้โดยตรงหรือผ่านบรรทัดคำสั่งมันจะล้มเหลวเนื่องจากพา ธ ของไฟล์ jar ที่ได้รับจากวิธีการด้านบนจะให้พา ธ ภายในในไฟล์ jar ซึ่งจะให้เส้นทางเสมอ เช่น
rsrc: project-name (บางทีฉันควรจะบอกว่ามันเป็นชื่อแพ็กเกจของไฟล์คลาสหลัก - คลาสที่ระบุ)
ฉันไม่สามารถแปลงเส้นทาง rsrc: ... ไปเป็นเส้นทางภายนอกนั่นคือเมื่อเรียกใช้ไฟล์ jar นอก Eclipse IDE จะไม่สามารถรับเส้นทางของไฟล์ jar ได้
วิธีเดียวที่เป็นไปได้สำหรับการรับพา ธ ของการรันไฟล์ jar นอก Eclipse IDE คือ
System.getProperty("java.class.path")
บรรทัดรหัสนี้อาจส่งคืนเส้นทางที่มีชีวิต (รวมถึงชื่อไฟล์) ของไฟล์ jar ที่กำลังทำงานอยู่ (โปรดทราบว่าเส้นทางส่งคืนไม่ใช่ไดเรกทอรีทำงาน) เนื่องจากเอกสาร java และบางคนบอกว่าจะคืนค่าพา ธ ของไฟล์คลาสทั้งหมด ในไดเรกทอรีเดียวกัน แต่จากการทดสอบของฉันหากในไดเรกทอรีเดียวกันมีไฟล์ jar จำนวนมากมันจะส่งคืนพา ธ ของการรัน jar เท่านั้น (เกี่ยวกับปัญหาหลายพา ธ ที่เกิดขึ้นจริงใน Eclipse)
java.class.path
สามารถมีหลายค่า หนึ่งค่าเหล่านั้นจะให้ไดเรกทอรีหรือไฟล์ JAR ซึ่งเป็นที่ตั้งของคลาสปัจจุบัน แต่อันไหน
คำตอบอื่น ๆ ดูเหมือนจะชี้ไปที่ซอร์สโค้ดซึ่งเป็นตำแหน่งไฟล์ Jar ซึ่งไม่ใช่ไดเรกทอรี
ใช้
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();
คำตอบที่เลือกข้างต้นจะไม่ทำงานหากคุณเรียกใช้ jar โดยคลิกที่คำตอบจากสภาพแวดล้อมเดสก์ท็อปของ Gnome (ไม่ใช่จากสคริปต์หรือเทอร์มินัลใด ๆ )
ฉันชอบที่วิธีต่อไปนี้ใช้ได้ทุกที่:
try {
return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
return "";
}
URLDecoder
ในการถอดรหัสอักขระพิเศษ โดยเฉพาะอย่างยิ่งตัวละครที่ชอบ+
จะถูกถอดรหัสไปยังช่องว่างอย่างผิดพลาด ดูคำตอบของฉันสำหรับรายละเอียด
NullPointerException
NPE
หากไม่มีทรัพยากรใน JAR
จริงๆแล้วที่นี่เป็นรุ่นที่ดีกว่า - อันเก่าล้มเหลวหากชื่อโฟลเดอร์มีที่ว่างอยู่
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);
}
สำหรับความล้มเหลวของแอพเพล็ตคุณจะไม่สามารถเข้าถึงไฟล์ในเครื่องได้ ฉันไม่รู้เกี่ยวกับ JWS มากนัก แต่การจัดการไฟล์ในเครื่องอาจเป็นไปไม่ได้ที่จะดาวน์โหลดแอพ
ฉันพยายามใช้ jar ที่ใช้เส้นทาง
String folder = MyClassName.class.getProtectionDomain().getCodeSource().getLocation().getPath();
c: \ app> java -jar application.jar
ใช้แอปพลิเคชัน jar ชื่อ "application.jar" บน Windows ในโฟลเดอร์ " c: \ app " ค่าของตัวแปร String "folder" คือ " \ c: \ app \ application.jar " และฉันประสบปัญหาในการทดสอบ ความถูกต้องของเส้นทาง
File test = new File(folder);
if(file.isDirectory() && file.canRead()) { //always false }
ดังนั้นฉันจึงพยายามกำหนด "ทดสอบ" เป็น:
String fold= new File(folder).getParentFile().getPath()
File test = new File(fold);
เพื่อให้ได้เส้นทางในรูปแบบที่ถูกต้องเช่น " c: \ app " แทนที่จะเป็น " \ c: \ app \ application.jar " และฉันสังเกตเห็นว่ามันใช้งานได้
ทางออกที่ง่ายที่สุดคือการส่งผ่านเส้นทางเป็นอาร์กิวเมนต์เมื่อใช้ขวด
คุณสามารถทำสิ่งนี้โดยอัตโนมัติด้วยเชลล์สคริปต์ (.bat ใน Windows, .sh ที่ใดก็ได้):
java -jar my-jar.jar .
ฉันเคย.
ผ่านไดเรกทอรีการทำงานปัจจุบัน
UPDATE
คุณอาจต้องการติดไฟล์ jar ในไดเรกทอรีย่อยดังนั้นผู้ใช้จะไม่คลิกมันโดยไม่ตั้งใจ รหัสของคุณควรตรวจสอบเพื่อให้แน่ใจว่ามีการระบุอาร์กิวเมนต์บรรทัดคำสั่งและให้ข้อความแสดงข้อผิดพลาดที่ดีหากอาร์กิวเมนต์หายไป
ฉันต้องยุ่งมากก่อนที่ฉันจะพบวิธีแก้ปัญหา (และสั้น) ในที่สุด
มันเป็นไปได้ว่าjarLocation
มาพร้อมกับคำนำหน้าเหมือนfile:\
หรือซึ่งสามารถถอดออกได้โดยใช้jar:file\
String#substring()
URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();
String path = getClass().getResource("").getPath();
พา ธ อ้างอิงถึงทรัพยากรภายในไฟล์ jar เสมอ
String path = new File(getClass().getResource("").getPath()).getParentFile().getParent(); File jarDir = new File(path.substring(5));
getResource("")
และgetResource(".")
ล้มเหลวในการทดสอบของฉันเมื่อเรียนอยู่ในไฟล์ JAR; การร้องขอทั้งสองคืนค่า 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;}
ทำงานได้ดีบน Windows
สิ่งที่น่าผิดหวังคือเมื่อคุณพัฒนาใน Eclipse MyClass.class.getProtectionDomain().getCodeSource().getLocation()
จะส่งคืน/bin
ไดเรกทอรีที่ยอดเยี่ยม แต่เมื่อคุณคอมไพล์ไปที่ jar เส้นทางจะมี/myjarname.jar
ส่วนที่ทำให้ชื่อไฟล์ผิดกฎหมาย
เพื่อให้โค้ดทำงานได้ทั้งใน IDE และเมื่อคอมไพล์ไปยัง jar ฉันใช้โค้ดต่อไปนี้:
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");
}
ไม่แน่ใจเกี่ยวกับคนอื่น ๆ แต่ในกรณีของฉันมันไม่ได้ทำงานกับ "Runnable jar" และฉันได้มันทำงานโดยการแก้ไขรหัสร่วมกันจากคำตอบ phchen2 และอื่น ๆ จากลิงค์นี้: วิธีการรับเส้นทางของไฟล์ JAR ทำงานอยู่? รหัส:
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");
ลองใช้วิธีแก้ปัญหาหลายวิธี แต่ไม่พบผลลัพธ์ที่ถูกต้องสำหรับกรณี (อาจเป็นพิเศษ) ที่ jar ที่รันได้ถูกเอ็กซ์พอร์ตด้วย "Packaging ภายนอกไลบรารี" ใน Eclipse ด้วยเหตุผลบางอย่างโซลูชันทั้งหมดที่ใช้โดเมน ProtectionDomain จะส่งผลให้ไม่มีค่าในกรณีนั้น
จากการรวมโซลูชันบางอย่างด้านบนฉันจัดการเพื่อให้ได้รหัสการทำงานต่อไปนี้:
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);
ลองสิ่งนี้:
String path = new File("").getAbsolutePath();
เมธอดนี้เรียกว่าจากรหัสในไฟล์เก็บถาวรส่งคืนโฟลเดอร์ที่ไฟล์. jar อยู่ มันควรจะทำงานได้ทั้งใน Windows หรือ 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);
}
มาจากรหัสที่: ตรวจสอบว่าทำงานจาก JAR
พูดถึงว่ามีการตรวจสอบเฉพาะในWindows
แต่ฉันคิดว่ามันทำงานได้ดีในระบบปฏิบัติการอื่น ๆ [ Linux,MacOs,Solaris
] :)
ฉันมี2 .jar
ไฟล์ในไดเรกทอรีเดียวกัน ฉันต้องการจาก.jar
ไฟล์หนึ่งเพื่อเริ่มต้นอื่น.jar
ไฟล์ซึ่งอยู่ในไดเรกทอรีเดียวกัน
ปัญหาคือว่าเมื่อคุณเริ่มต้นจากไดเรกทอรีปัจจุบันคือcmd
system32
คำเตือน!
;][[;'57f2g34g87-8+9-09!2#@!$%^^&()
หรือ()%&$%^@#
ใช้งานได้ดีProcessBuilder
กับด้านล่างดังต่อไปนี้:🍂 ..
//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;
}
รหัสนี้เหมาะกับฉัน:
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;
}
รหัสนี้ทำงานสำหรับฉันเพื่อระบุว่าโปรแกรมจะถูกดำเนินการภายในไฟล์ JAR หรือ 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;
}
}
หากฉันต้องการเส้นทางแบบเต็มของไฟล์ JAR ของ Windows ฉันใช้วิธีนี้:
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;
}
}
รหัสที่สมบูรณ์ของฉันทำงานกับแอพพลิเคชั่น Spring Boot โดยใช้CommandLineRunner
การติดตั้งเพื่อให้แน่ใจว่าแอปพลิเคชันจะถูกดำเนินการภายในมุมมองคอนโซล (ดับเบิลคลิกโดยไม่ตั้งใจในชื่อไฟล์ JAR) ฉันกำลังใช้รหัสถัดไป:
@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;
}
}
}
ฉันเขียนใน Java 7 และทดสอบใน Windows 7 ด้วยรันไทม์ของ Oracle และ Ubuntu พร้อมรันไทม์โอเพนซอร์ส สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบสำหรับระบบเหล่านั้น:
พา ธ สำหรับไดเร็กทอรีพาเรนต์ของไฟล์ jar ใด ๆ ที่กำลังรัน (สมมติว่าคลาสเรียกใช้โค้ดนี้เป็นชายด์โดยตรงของไฟล์เก็บถาวร 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
ดังนั้นเส้นทางของ foo.jar น่าจะเป็น:
fooPath = fooDirPath + File.separator + "foo.jar";
นี่ไม่ใช่การทดสอบบน Mac หรือ Windows ที่เก่ากว่า
getProtectionDomain
วิธีการอาจจะไม่ทำงานในบางครั้งเช่นเมื่อคุณต้องไปหาขวดสำหรับบางส่วนของการเรียนภาษาจาวาหลัก (เช่นในกรณีของฉันStringBuilder
ระดับภายใน IBM JDK) ทำงานอย่างไรต่อไปได้อย่างราบรื่น:
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, "");
}
ฉันมีวิธีอื่นในการรับตำแหน่ง String ของคลาส
URL path = Thread.currentThread().getContextClassLoader().getResource("");
Path p = Paths.get(path.toURI());
String location = p.toString();
สตริงเอาต์พุตจะมีรูปแบบของ
C:\Users\Administrator\new Workspace\...
ช่องว่างและตัวละครอื่น ๆ file:/
ได้รับการจัดการและในรูปแบบโดยไม่ต้อง ดังนั้นจะง่ายต่อการใช้งาน