2009-06-02 17 views
123

Próbuję uzyskać ścieżkę do zasobu, ale nie miałem szczęścia.Jak uzyskać ścieżkę do zasobu w pliku JAR Java

Działa to (zarówno w IDE i JAR), ale w ten sposób nie można uzyskać ścieżkę do pliku, tylko zawartość pliku:

ClassLoader classLoader = getClass().getClassLoader(); 
PrintInputStream(classLoader.getResourceAsStream("config/netclient.p")); 

Gdybym to zrobić:

ClassLoader classLoader = getClass().getClassLoader(); 
File file = new File(classLoader.getResource("config/netclient.p").getFile()); 

wynikiem jest: java.io.FileNotFoundException: file:/path/to/jarfile/bot.jar!/config/netclient.p (No such file or directory)

Czy istnieje sposób, aby uzyskać ścieżkę do pliku zasobów?

+0

mogę zapytać, dlaczego trzeba ścieżkę? –

+1

Tak. Mam klasę, którą chciałbym pracować z obydwoma, folder na zewnątrz (na wypadek, gdy chcę zmienić jakiś parametr pliku konfiguracyjnego) i JAR, który ukrywa pliki konfiguracji implementacji dla użytkownika (jak dystrybuowalny JAR dla wszystkich ludzi). –

+1

Tak więc klasa otrzymuje właśnie PATH do pliku (pliku konfiguracyjnego). –

Odpowiedz

62

Jest to celowe. Zawartość "pliku" może nie być dostępna jako plik. Pamiętaj, że masz do czynienia z klasami i zasobami, które mogą być częścią pliku JAR lub innego rodzaju zasobu. Program ładujący klasy nie musi zapewniać obsługi pliku dla zasobu, na przykład plik jar może nie zostać rozszerzony na pojedyncze pliki w systemie plików.

Cokolwiek można zrobić, pobierając plik java.io.File można zrobić, kopiując strumień do pliku tymczasowego i robiąc to samo, jeśli plik java.io.file jest absolutnie niezbędny.

+4

możesz dodać "rsrc:", gdy zadzwonisz do zasobu, aby go otworzyć. tak jak nowy plik ("rsrc: nazwapliku.txt") ładuje plik filename.txt, który jest zapakowany wewnątrz korzenia twojego słoja. – molokoV

7

jeśli netclient.p znajduje się wewnątrz pliku JAR, nie będzie ścieżki, ponieważ ten plik znajduje się w innym pliku. w takim przypadku najlepszą ścieżką, jaką możesz mieć, jest naprawdę file:/path/to/jarfile/bot.jar!/config/netclient.p.

2

Plik jest abstrakcją dla pliku w systemie plików, a systemy plików nie wiedzą nic o zawartości pliku JAR.

Spróbuj z URI, myślę, że istnieje słoik: // protokół, który może być przydatny dla twoich celów.

6

Musisz zrozumieć ścieżkę w pliku jar.
Po prostu odwołaj się do niego względnie. Więc jeśli masz plik (myfile.txt), znajdujący się w pliku foo.jar pod katalogiem \src\main\resources (styl maven). Można by odnieść się do niego jak:

src/main/resources/myfile.txt 

Jeśli zrzucić swój dzban przy użyciu jar -tvf myjar.jar widać wyjście i względną ścieżkę w pliku jar i użyć ukośniki.

+0

Rzeczywiście musisz używać ukośników, nawet w systemie Windows. Oznacza to, że nie można używać 'File.separator'. – str

12

Spędziłem trochę czasu na tym problemie, ponieważ żadne rozwiązanie, które znalazłem, nie działało, o dziwo! Katalog roboczy często nie jest katalogiem JAR, szczególnie jeśli JAR (lub jakikolwiek program, jeśli o to chodzi) uruchamiany jest z Menu Start w Windows. Oto, co zrobiłem i działa na pliki .class uruchomione spoza JAR, tak samo jak działa na JAR. (I tylko przetestowane pod Windows 7.)

try { 
    //Attempt to get the path of the actual JAR file, because the working directory is frequently not where the file is. 
    //Example: file:/D:/all/Java/TitanWaterworks/TitanWaterworks-en.jar!/TitanWaterworks.class 
    //Another example: /D:/all/Java/TitanWaterworks/TitanWaterworks.class 
    PROGRAM_DIRECTORY = getClass().getClassLoader().getResource("TitanWaterworks.class").getPath(); // Gets the path of the class or jar. 

    //Find the last ! and cut it off at that location. If this isn't being run from a jar, there is no !, so it'll cause an exception, which is fine. 
    try { 
     PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('!')); 
    } catch (Exception e) { } 

    //Find the last/and cut it off at that location. 
    PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('/') + 1); 
    //If it starts with /, cut it off. 
    if (PROGRAM_DIRECTORY.startsWith("/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(1, PROGRAM_DIRECTORY.length()); 
    //If it starts with file:/, cut that off, too. 
    if (PROGRAM_DIRECTORY.startsWith("file:/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(6, PROGRAM_DIRECTORY.length()); 
} catch (Exception e) { 
    PROGRAM_DIRECTORY = ""; //Current working directory instead. 
} 
1

To, co zostało powiedziane, nie optymalny sposób, aby załadować zasobów, ale jeśli koniecznie musi mieć java.io.File odniesienia, a następnie spróbuj następujących:

URL url = null; 
    try { 
    URL baseUrl = YourClass.class.getResource("."); 
    if (baseUrl != null) { 
     url = new URL(baseUrl, "yourfilename.ext"); 
    } else { 
     url = YourClass.class.getResource("yourfilename.ext"); 
    } 
    } catch (MalformedURLException e) { 
    // Do something appropriate 
    } 

Daje to java.net.URL i może być używany w konstruktorze java.io.File.

+0

To nie działa. Kiedy robisz nowy plik (url.toURI()), dostajesz java.lang.IllegalArgumentException: URI nie jest hierarchiczny, gdy plik znajduje się w słoiku. –

1

następującą ścieżkę pracował dla mnie: classpath:/path/to/resource/in/jar

+0

Czy to działa z ikonami dla JButtons? –

+0

@Anatoly Czy mógłbyś udostępnić więcej datails powyżej –

39

Podczas ładowania zasobu upewnij się zauważyć różnicę pomiędzy:

getClass().getClassLoader().getResource("com/myorg/foo.jpg") //relative path 

i

getClass().getResource("/com/myorg/foo.jpg")); //note the slash at the beginning 

jak sądzę, to zamieszanie powoduje większość problemów podczas ładowania zasobu. Podczas wczytywania obraz jest łatwiejszy w użyciu getResourceAsStream():

BufferedImage image = ImageIO.read(getClass().getResourceAsStream("/com/myorg/foo.jpg")); 

kiedy naprawdę trzeba załadować plik (bez obrazu) z archiwum JAR, możesz spróbować tego:

File file = null; 
    String resource = "/com/myorg/foo.xml"; 
    URL res = getClass().getResource(resource); 
    if (res.toString().startsWith("jar:")) { 
     try { 
      InputStream input = getClass().getResourceAsStream(resource); 
      file = File.createTempFile("tempfile", ".tmp"); 
      OutputStream out = new FileOutputStream(file); 
      int read; 
      byte[] bytes = new byte[1024]; 

      while ((read = input.read(bytes)) != -1) { 
       out.write(bytes, 0, read); 
      } 
      file.deleteOnExit(); 
     } catch (IOException ex) { 
      Exceptions.printStackTrace(ex); 
     } 
    } else { 
     //this will probably work in your IDE, but not from a JAR 
     file = new File(res.getFile()); 
    } 

    if (file != null && !file.exists()) { 
     throw new RuntimeException("Error: File " + file + " not found!"); 
    } 
+1

+1 To działało dla mnie. Upewnij się, że umieściłeś pliki, które chcesz odczytywać w folderze 'bin' i przejdź do katalogu ładowania klas w zasobach przed użyciem ścieżki' /com/myorg/filename.ext '. – rayryeng

+0

+1 To również działa dla mnie ... Rozumiem, że mogą istnieć pewne zagrożenia bezpieczeństwa związane z tym podejściem, więc właściciele aplikacji muszą być tego świadomi. – LucasA

+0

Czy możesz wyjaśnić to stwierdzenie "Zawsze lepiej załadować zasób za pomocą getResourceAsStream()"? W jaki sposób może to rozwiązać problem? –

0

Kiedy znajduje się w pliku JAR, zasób znajduje się absolutnie w hierarchii pakietów (nie hierarchii systemu plików). Więc jeśli masz klasę com.przykład. Ściągnij zasób o nazwie "./default.conf", nazwa zasobu jest określona jako "/com/example/default.conf".

Ale czy to w słoiku to nie jest plik ...

1
private static final String FILE_LOCATION = "com/input/file/somefile.txt"; 

//Method Body 


InputStream invalidCharacterInputStream = URLClassLoader.getSystemResourceAsStream(FILE_LOCATION); 

Getting to od getSystemResourceAsStream jest najlepszym rozwiązaniem. Uzyskanie strumienia wejściowego zamiast pliku lub adresu URL działa w pliku JAR i działa samodzielnie.

15

Jedna linia odpowiedź brzmi -

String path = this.getClass().getClassLoader().getResource(<resourceFileName>).toExternalForm() 

Zasadniczo getResource metoda daje URL. Od tego adresu URL można wyodrębnić ścieżkę przez wywołanie toExternalForm()

Referencje:

getResource(), toExternalForm()

+1

Podczas działania z mojego środowiska (IntelliJ) generuje prosty adres URL pliku, który działa we wszystkich przypadkach. Jednak podczas działania z samego słoika otrzymuję URI podobny do jar: file: /path/to/jar/jarname.jar! /file_in_jar.mp4 Nie wszystko może wykorzystywać URI, który zaczyna się od słoika.Jeśli chodzi o JavaFX Media, –

+1

Najbardziej podoba mi się ta odpowiedź. w większości przypadków lepiej jest po prostu pobrać InputStream do zasobu, gdy znajduje się on w pliku jar, ale jeśli z jakiegoś powodu naprawdę potrzebujesz ścieżki, to właśnie działa. Potrzebowałem ścieżki do udostępnienia obiektu innej firmy . Więc dziękuję! – Mario

2

Jest to ten sam kod od użytkownika Tombart ze strumieniem spłukiwania i blisko, aby uniknąć niekompletne tymczasowy zawartość pliku kopii od jar resource i mieć unikalne nazwy plików tymczasowych.

 File file = null; 
     String resource = "/view/Trial_main.html" ; 
     URL res = getClass().getResource(resource); 
     if (res.toString().startsWith("jar:")) { 
      try { 
       InputStream input = getClass().getResourceAsStream(resource); 
       file = File.createTempFile(new Date().getTime()+"", ".html"); 
       OutputStream out = new FileOutputStream(file); 
       int read; 
       byte[] bytes = new byte[1024]; 

       while ((read = input.read(bytes)) != -1) { 
        out.write(bytes, 0, read); 
       } 
       out.flush(); 
       out.close(); 
       input.close(); 
       file.deleteOnExit(); 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 
     } else { 
      //this will probably work in your IDE, but not from a JAR 
      file = new File(res.getFile()); 
     } 
2

W moim przypadku użyłem obiektu URL zamiast ścieżki.

pliku

File file = new File("my_path"); 
URL url = file.toURI().toURL(); 

zasobu w ścieżce klasy używając classloader

URL url = MyClass.class.getClassLoader().getResource("resource_name") 

Kiedy trzeba czytać treść, można użyć następującego kodu:

InputStream stream = url.openStream(); 

I możesz uzyskać dostęp do zawartości za pomocą metody InputStream.

0

wewnątrz Zasoby folderu (Java/main/zasobów) swojego słoika dodać plik (zakładamy, że dodałeś plik XML o nazwie imports.xml), potem wstrzyknąć ResourceLoader jeśli używasz wiosna jak poniżej

@Autowired 
private ResourceLoader resourceLoader; 

wewnątrz funkcji turystycznej napisać kod miech w celu załadowania pliku:

Resource resource = resourceLoader.getResource("classpath:imports.xml"); 
    try{ 
     File file; 
     file = resource.getFile();//will load the file 
... 
    }catch(IOException e){e.printStackTrace();} 
Powiązane problemy