ฉันจะรับทรัพยากร "โฟลเดอร์" จากในไฟล์ jar ของฉันได้อย่างไร


139

ฉันมีโฟลเดอร์ทรัพยากร / แพ็คเกจในรากของโครงการของฉันฉัน "ไม่" ต้องการโหลดไฟล์บางไฟล์ ถ้าฉันต้องการโหลดไฟล์บางไฟล์ฉันจะใช้ class.getResourceAsStream และฉันจะสบายดี !! สิ่งที่ฉันต้องการทำจริง ๆ คือการโหลด "โฟลเดอร์" ในโฟลเดอร์ทรัพยากรวนไฟล์ในโฟลเดอร์นั้นและรับกระแสข้อมูลไปยังแต่ละไฟล์และอ่านเนื้อหา ... สมมติว่าชื่อไฟล์ไม่ได้ถูกกำหนดก่อนรันไทม์ ... ฉันควรทำอย่างไรดี? มีวิธีรับรายการไฟล์ภายในโฟลเดอร์ในไฟล์ jar ของคุณหรือไม่? โปรดสังเกตว่าไฟล์ Jar ที่มีทรัพยากรเป็นไฟล์ jar เดียวกันกับที่โค้ดกำลังรัน ...

ขอบคุณล่วงหน้า...


1
สิ่งนี้จะช่วยได้: stackoverflow.com/questions/1529611/…
Jigar Joshi

ดูเพิ่มเติมได้ที่: stackoverflow.com/questions/4764347/…
Jigar Joshi

5
สิ่งแรกคือเกี่ยวกับการแตกไฟล์ jar ซึ่งเป็นสิ่งสุดท้ายที่ฉันต้องการลองเช่นสถานการณ์ที่แย่ลงมาถึงแย่ลง !! หากฉันต้องการแตกไฟล์ฉันจะใส่มันไว้ในโฟลเดอร์การติดตั้งตอนติดตั้ง! ฉันต้องการเข้าถึงพวกเขาจากภายใน jar และเหตุผลของฉันคือถ้า getResourceAsStream สามารถเข้าถึงไฟล์ได้ Java ควรจะสามารถสำรวจโฟลเดอร์ใน jar นั้นได้โดยไม่จำเป็นต้องแตกไฟล์ !! แต่ขอบคุณ ...
Mostafa Zeinali

คำตอบ:


111

ในที่สุดฉันก็พบวิธีแก้ปัญหา:

final String path = "sample/folder";
final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath());

if(jarFile.isFile()) {  // Run with JAR file
    final JarFile jar = new JarFile(jarFile);
    final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
    while(entries.hasMoreElements()) {
        final String name = entries.nextElement().getName();
        if (name.startsWith(path + "/")) { //filter according to the path
            System.out.println(name);
        }
    }
    jar.close();
} else { // Run with IDE
    final URL url = Launcher.class.getResource("/" + path);
    if (url != null) {
        try {
            final File apps = new File(url.toURI());
            for (File app : apps.listFiles()) {
                System.out.println(app);
            }
        } catch (URISyntaxException ex) {
            // never happens
        }
    }
}

บล็อกที่สองใช้งานได้เมื่อคุณรันแอปพลิเคชันบน IDE (ไม่ใช่ไฟล์ jar) คุณสามารถลบออกได้หากคุณไม่ชอบ


อัปเดตคำตอบที่ถูกต้อง แม้ว่านี่จะไม่ใช่สิ่งที่ฉันต้องการจะทำโดยเฉพาะอย่างยิ่งในรหัสที่มีไฟล์ต้นฉบับ 34,000+ รายการ ... แต่ดูเหมือนจะเป็นทางออกเดียว ขอบคุณ.
Mostafa Zeinali

4
FYI สิ่งนี้ใช้ไม่ได้หากเปิดจาก webstart เนื่องจาก getPath ส่งคืนบางสิ่งที่สัมพันธ์กับโดเมนของเซิร์ฟเวอร์
amos

1
อย่าคิดว่ามันจะทำงานถ้า path อยู่ใน jar จะให้ข้อผิดพลาดนี้กับการแปลง toURI: java.lang.IllegalArgumentException: URI ไม่ใช่ลำดับชั้น
tribbloid

4
ใช้งานได้กับไฟล์ jar เดี่ยวเท่านั้นไม่สามารถแยกทรัพยากรออกจากการอ้างอิงใน jar อื่นได้
tribbloid

2
นี่ไม่ใช่วิธีแก้ปัญหาที่ปลอดภัยเพราะ: 1. ถือว่าไฟล์. jar เป็นไฟล์โลคัลบนระบบเดียวกัน 2. URL.getPath () ไม่ส่งคืนชื่อไฟล์ที่ถูกต้อง แต่จะส่งคืนส่วนของเส้นทางของ URL โดยที่เปอร์เซ็นต์การยกเว้นทั้งหมดยังคงอยู่ 3. ProtectionDomain.getCodeSource () สามารถกลับ null
VGR

14

ลองทำสิ่งต่อไปนี้
สร้างพา ธ ของทรัพยากร"<PathRelativeToThisClassFile>/<ResourceDirectory>" เช่นหากคลาสพา ธ ของคุณคือ com.abc.package.MyClass และไฟล์ resoure ของคุณอยู่ใน src / com / abc / package / resources /:

URL url = MyClass.class.getResource("resources/");
if (url == null) {
     // error - missing folder
} else {
    File dir = new File(url.toURI());
    for (File nextFile : dir.listFiles()) {
        // Do something with nextFile
    }
}

คุณยังสามารถใช้

URL url = MyClass.class.getResource("/com/abc/package/resources/");

27
ขอบคุณสำหรับเวลาและความพยายาม แต่สิ่งนี้ไม่ทำงานเมื่อรหัสของคุณอยู่ในไฟล์. jar และทรัพยากรของคุณอยู่ในไฟล์. jar นั้นด้วย เมื่อคุณอยู่ในไฟล์. jar คุณจะไม่สามารถสร้างไฟล์ () และคุณจะไม่สามารถรับ URL สำหรับโฟลเดอร์นั้น ... ฉันเองก็รู้สึกสงบและมีรายการไฟล์แต่ละไฟล์ใน XML ... ฉันไม่ได้ ไม่คิดว่าคุณสามารถทำได้สำหรับโฟลเดอร์ในไฟล์ jar เลย ...
Mostafa Zeinali

2
ขออภัยที่คุณมีปัญหา อย่างไรก็ตามมันใช้งานได้จริงเมื่อฐานรหัสของคุณอยู่ในไฟล์ jar และทรัพยากรของคุณจะอยู่ในไฟล์ jar นั้นด้วย คุณไม่ได้สร้างไฟล์ () บนดิสก์ - คุณกำลังอ่านไฟล์ภายในไฟล์ jar ในหน่วยความจำจาวา โปรดทราบว่า ClassLoader ยินดีที่จะปฏิบัติกับไฟล์ jar เทียบเท่ากับไดเรกทอรีบนดิสก์ นี่คือรายละเอียดจากแหล่งที่มา:
เกล็นที่ดีที่สุด

1
เพิ่งรันโค้ดบน jar และได้รับข้อผิดพลาด ... อ๊ะ V ขอโทษที่ไม่ดีของฉัน ต้องจัดการพา ธ URL ของ jar ด้วย "ไฟล์: ... ! / dir1 / dir2 ... " การแก้ไขสองประการ: stackoverflow.com/questions/1429172/… หรือ String jarPath = dirURL.getPath (). substring (5, dirURL.getPath (). indexOf ("!")); JarFile jar = ใหม่ JarFile (URLDecoder.decode (jarPath, "UTF-8")); การแจงนับ <JarEntry> รายการ = jar.entries (); ในขณะที่ (รายการ.hasMoreElements ()) {// ทำอะไรบางอย่าง}
เกลนที่ดีที่สุด

3
จาก javadoc เป็นที่ชัดเจนว่าวิธีการไม่ได้รับประกันว่าจะส่งคืนไฟล์ภายใต้สถานการณ์ทั้งหมด แต่ถ้าคุณอ่าน Q จริงๆแล้ว OP รับประกันว่าจะทำงานกับไฟล์และโฟลเดอร์ได้ 100% โดยการสร้าง ถามว่าจะขอเข้าถึงไดเรคทอรีและไฟล์ได้อย่างไร - นี่เป็นสิ่งที่เฉพาะเจาะจงยิ่งขึ้นกว่าการสรุปทั่วไปของ API การแปลงเป็นไฟล์มีความเหมาะสมและถูกต้องเพื่อตอบสนองความต้องการ โปรดอ่านคำถามอย่างถูกต้องก่อนโพสต์ความคิดเห็นที่ตรงกันข้ามอย่างยิ่ง ไชโย
เกลนสุดยอด

7
OP ไม่ทำงานกับไฟล์และไดเรกทอรี เขากำลังทำงานกับทรัพยากรในไฟล์ JAR รีซอร์สในไฟล์ JAR ไม่ใช่ไฟล์หรือไดเร็กทอรีและไม่สามารถแสดงรายการกับFileคลาส รหัสนี้ใช้ไม่ได้กับทรัพยากรที่อยู่ในไฟล์ JAR ระยะเวลา
มาร์ควิสแห่งลอร์น

7

ฉันรู้ว่านี่เป็นเวลาหลายปีที่ผ่านมา แต่สำหรับคนอื่นมาเจอเรื่องนี้ สิ่งที่คุณสามารถทำได้คือใช้getResourceAsStream()เมธอดที่มีพา ธ ของไดเรกทอรีและอินพุตสตรีมจะมีชื่อไฟล์ทั้งหมดจาก dir นั้น หลังจากนั้นคุณสามารถเชื่อมต่อพา ธ dir กับแต่ละชื่อไฟล์และเรียกใช้ getResourceAsStream สำหรับแต่ละไฟล์ในลูป


7
วิธีนี้ใช้งานได้ดีเว้นแต่ว่าคุณวางแผนที่จะสั่นสะเทือนสิ่งที่เกิดขึ้น
Tustin2121

1
ฉันคิดว่านี่ควรเป็นโซลูชันที่ได้รับการยอมรับเนื่องจากสะอาดและไม่จำเป็นต้องจัดการกับ jar และ IDE ในแต่ละกรณี แม้ว่าฉันไม่แน่ใจว่าทำไม getResource ไม่พบโฟลเดอร์ แต่ getResourceAsStream ทำ
Raghuram Onti Srinivasan

6

ฉันมีปัญหาเดียวกันอยู่ในมือขณะที่ฉันพยายามโหลดการกำหนดค่า hadoop บางอย่างจากทรัพยากรที่บรรจุในขวด ... ทั้ง IDE และบน jar (รุ่นที่วางจำหน่าย)

ฉันพบว่าjava.nio.file.DirectoryStreamทำงานได้ดีที่สุดในการวนซ้ำเนื้อหาไดเรกทอรีทั้งในระบบไฟล์และ jar

String fooFolder = "/foo/folder";
....

ClassLoader classLoader = foofClass.class.getClassLoader();
try {
    uri = classLoader.getResource(fooFolder).toURI();
} catch (URISyntaxException e) {
    throw new FooException(e.getMessage());
} catch (NullPointerException e){
    throw new FooException(e.getMessage());
}

if(uri == null){
    throw new FooException("something is wrong directory or files missing");
}

/** i want to know if i am inside the jar or working on the IDE*/
if(uri.getScheme().contains("jar")){
    /** jar case */
    try{
        URL jar = FooClass.class.getProtectionDomain().getCodeSource().getLocation();
        //jar.toString() begins with file:
        //i want to trim it out...
        Path jarFile = Paths.get(jar.toString().substring("file:".length()));
        FileSystem fs = FileSystems.newFileSystem(jarFile, null);
        DirectoryStream<Path> directoryStream = Files.newDirectoryStream(fs.getPath(fooFolder));
        for(Path p: directoryStream){
            InputStream is = FooClass.class.getResourceAsStream(p.toString()) ;
        performFooOverInputStream(is);
        /** your logic here **/
            }
    }catch(IOException e) {
        throw new FooException(e.getMessage());     
    }
}
else{
    /** IDE case */
    Path path = Paths.get(uri);
    try {
        DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path);
        for(Path p : directoryStream){
            InputStream is = new FileInputStream(p.toFile());
            performFooOverInputStream(is);
        }
    } catch (IOException _e) {
        throw new FooException(_e.getMessage());
    }
}

มันใช้ได้ดีสำหรับฉัน เฉพาะฉันเท่านั้นที่เปลี่ยน 'Path jarFile = Paths.get (jar.toString (). substring ("file:". length ()));' ด้วย 'เส้นทาง jarFile = Paths.get (jar.toURI ());' เพื่อให้มันทำงานใน Windows นอกจากนี้ยังใช้ลองกับคำสั่งทรัพยากรสำหรับวัตถุ FileSystem
Jarle Jacobsen

สิ่งนี้ได้ผลสำหรับฉัน! ฉันใช้แอพพลิเคชั่น dropwizard ใน docker
nikunj

4

รหัสต่อไปนี้จะคืนค่า "โฟลเดอร์" ที่ต้องการเป็นเส้นทางโดยไม่คำนึงว่าอยู่ในขวดหรือไม่

  private Path getFolderPath() throws URISyntaxException, IOException {
    URI uri = getClass().getClassLoader().getResource("folder").toURI();
    if ("jar".equals(uri.getScheme())) {
      FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap(), null);
      return fileSystem.getPath("path/to/folder/inside/jar");
    } else {
      return Paths.get(uri);
    }
  }

ต้องใช้ Java 7+


ดี! ฉันต้องเพิ่มว่า FileSystem นั้นสามารถปิดได้ซึ่งหมายความว่าคุณต้องปิดมันในบางจุดเพื่อเพิ่มทรัพยากรระบบ แน่นอนเส้นทางที่กลับมาจะใช้งานไม่ได้ทันทีหลังจากนั้น
Kirill Gamazkov

โปรดทราบว่าในกรณีของไฟล์ jar ชื่อของทรัพยากร (ที่นี่แพ็คเกจ + folder) ดูเหมือนจะถูกละเว้นเมื่อสร้างระบบไฟล์ ดังนั้นจึงgetPathไม่กลับมาแต่เพียงfolder/path/to/... path/to/...
Marcono1234

1

อีกวิธีหนึ่งคุณสามารถทำได้โดยใช้ResourceLoaderสิ่งนี้:

import org.springframework.core.io.Resource;
import org.apache.commons.io.FileUtils;

@Autowire
private ResourceLoader resourceLoader;

...

Resource resource = resourceLoader.getResource("classpath:/path/to/you/dir");
File file = resource.getFile();
Iterator<File> fi = FileUtils.iterateFiles(file, null, true);
while(fi.hasNext()) {
    load(fi.next())
}

0

ง่าย ๆ ... ใช้ OSGi ใน OSGi คุณสามารถวนซ้ำรายการของ Bundle ด้วย findEntries และ findPaths


10
หากมันเกี่ยวข้องกับ OSGI ฉันแทบจะไม่เรียกมันว่า 'เรียบง่าย' แต่ถ้าคุณบังเอิญใช้ OSGI อยู่แล้ว ... ใช่แน่นอน แต่แนะนำให้ย้ายไปที่ OSGI เพียงเพื่อแก้ปัญหานี้โดยเฉพาะดูเหมือนว่าจะมากเกินไป
กริช

OSGi ยังแก้ไขปัญหาอื่น ๆ อีกมากมายและในปัจจุบันมันง่ายมากในการเริ่มต้น ดูแบบฝึกหัด OSGi enRoute
Peter Kriens

ฉันจะอยู่ห่างจาก OSGi ถ้าคุณไม่จำเป็นต้องใช้มัน Bloatware ที่ออกแบบมาเพื่อแก้ไขปัญหาการปรับใช้ของ IMO 90s
user2337270

-1

ภายในไฟล์ jar ของฉันฉันมีโฟลเดอร์ชื่อว่าอัปโหลดโฟลเดอร์นี้มีไฟล์ข้อความอีกสามไฟล์อยู่ข้างในและฉันจำเป็นต้องมีโฟลเดอร์และไฟล์เดียวกันนอกไฟล์ jar ฉันใช้รหัสด้านล่างนี้:

URL inputUrl = getClass().getResource("/upload/blabla1.txt");
File dest1 = new File("upload/blabla1.txt");
FileUtils.copyURLToFile(inputUrl, dest1);

URL inputUrl2 = getClass().getResource("/upload/blabla2.txt");
File dest2 = new File("upload/blabla2.txt");
FileUtils.copyURLToFile(inputUrl2, dest2);

URL inputUrl3 = getClass().getResource("/upload/blabla3.txt");
File dest3 = new File("upload/Bblabla3.txt");
FileUtils.copyURLToFile(inputUrl3, dest3);

1
สวัสดีขอบคุณสำหรับคำตอบ แต่คุณเห็นคุณจำเป็นต้องรู้ชื่อของแต่ละไฟล์ในโฟลเดอร์นั้นเมื่อเขียนรหัส และคุณต้องตั้งชื่อให้แต่ละคนอย่างชัดเจน สิ่งที่ฉันกำลังมองหาคือวิธีการวนซ้ำไฟล์ในโฟลเดอร์และรับชื่อของพวกเขาใน runtime ดังนั้นฉันสามารถเพิ่มทรัพยากรไปยังโฟลเดอร์โดยไม่ต้องเปลี่ยนรหัสรู้รหัสจะประมวลผลพวกเขาด้วย ขอบคุณสำหรับเวลาของคุณ : 3
Mostafa Zeinali

-1

ตามที่คำตอบอื่น ๆ ชี้ให้เห็นเมื่อทรัพยากรอยู่ในไฟล์ jar สิ่งต่าง ๆ น่าเกลียดมาก ในกรณีของเราวิธีนี้:

https://stackoverflow.com/a/13227570/516188

ทำงานได้ดีมากในการทดสอบ (เนื่องจากเมื่อการทดสอบรันโค้ดไม่ได้บรรจุในไฟล์ jar) แต่ไม่ทำงานเมื่อแอปทำงานตามปกติ ดังนั้นสิ่งที่ฉันทำคือ ... ฉัน hardcode รายชื่อไฟล์ในแอพ แต่ฉันมีการทดสอบที่อ่านรายการจริงจากดิสก์ (สามารถทำได้ตั้งแต่ที่ทำงานในการทดสอบ) และล้มเหลวหากรายการจริงไม่ได้ ไม่ตรงกับรายการที่แอปส่งคืน

ด้วยวิธีนี้ฉันมีรหัสง่าย ๆ ในแอพของฉัน (ไม่มีลูกเล่น) และฉันแน่ใจว่าฉันไม่ลืมที่จะเพิ่มรายการใหม่ในรายการด้วยการทดสอบ


-25

ลิงค์นี้จะบอกวิธี

มายากลคือเมธอด getResourceAsStream ():

InputStream is = 
this.getClass().getClassLoader().getResourceAsStream("yourpackage/mypackage/myfile.xml")

20
ไม่มีเพื่อน!! ฉันไม่ต้องการไฟล์เดียว !! ฉันต้องการทั้งโฟลเดอร์ซึ่งมีไฟล์ย่อยที่ไม่ได้กำหนดเวลาทำงานล่วงหน้า !!!
Mostafa Zeinali
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.