2009-06-02 1 views
123

Я пытаюсь получить путь к ресурсу, но мне не повезло.Как получить путь к ресурсу в Java JAR-файле

Это работает (как в IDE и с JAR), но таким образом я не могу получить путь к файлу, только содержимое файла:

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

Если я делаю это:

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

результат: java.io.FileNotFoundException: file:/path/to/jarfile/bot.jar!/config/netclient.p (No such file or directory)

есть ли способ, чтобы получить путь к файлу ресурсов?

+0

Могу ли я спросить, почему вы должны путь? –

+1

Да. У меня есть класс, с которым мне хотелось бы работать как с внешней, так и с другой (в случае, если я хочу изменить какой-либо параметр конфигурационного файла) и JAR, который скрывает файлы конфигурации реализации для пользователя (например, распространяемый JAR для всех людей). –

+1

Таким образом, класс просто получает PATH в файл (файл конфигурации). –

ответ

62

Это преднамеренное. Содержимое «файла» может быть недоступно в виде файла. Помните, что вы имеете дело с классами и ресурсами, которые могут быть частью файла JAR или другого ресурса. Погрузчик классов не должен предоставлять дескриптор файла для ресурса, например, файл jar, возможно, не был расширен в отдельные файлы в файловой системе.

Все, что вы можете сделать, получив java.io.File, можно сделать, скопировав поток во временный файл и сделав то же самое, если java.io.File абсолютно необходим.

+4

вы можете добавить 'rsrc:', когда вы вызываете свой ресурс, чтобы открыть его. как новый файл («rsrc: filename.txt»), это будет загружать файл filename.txt, который упакован в корень вашей банки – molokoV

7

Если netclient.p находится внутри JAR-файла, у него не будет пути, потому что этот файл находится внутри другого файла. в этом случае лучший путь, который у вас есть, - это действительно file:/path/to/jarfile/bot.jar!/config/netclient.p.

2

Файл является абстракцией для файла в файловой системе, и файловые системы ничего не знают о содержимом JAR.

Попробуйте использовать URI, я думаю, что есть протокол jar: //, который может быть полезен для ваших purpouses.

6

Вам необходимо понять путь в файле jar.
Просто обратитесь к этому вопросу. Поэтому, если у вас есть файл (myfile.txt), расположенный в foo.jar в каталоге \src\main\resources (стиль maven). Вы бы относиться к нему, как:

src/main/resources/myfile.txt 

Если вы дамп банку с помощью jar -tvf myjar.jar вы увидите выход и относительный путь в файле фляги, и использовать слэша.

+0

Вам действительно нужно использовать косые черты даже в Windows. Это означает, что вы не можете использовать 'File.separator'. – str

12

Я провел некоторое время с этой проблемой, потому что никакое решение, которое я нашел, действительно работало, как ни странно! Рабочий каталог часто не является каталогом JAR, особенно если JAR (или любая программа, если на то пошло) запускается из меню «Пуск» под Windows. Итак, вот что я сделал, и он работает для .class-файлов, запускаемых извне JAR так же хорошо, как и для JAR. (Я проверил его только под 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

Это, на это было сказано, не оптимальный способ загрузки ресурсов, но если вы абсолютно необходимо иметь java.io.File ссылку, то попробуйте следующее:

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 
    } 

Это дает вам java.net.URL и может использоваться в конструкторе java.io.File.

+0

Это не работает. Когда вы делаете новый файл (url.toURI()), вы получаете java.lang.IllegalArgumentException: URI не является иерархическим, когда файл находится в банке. –

1

Следующий путь работал для меня: classpath:/path/to/resource/in/jar

+0

Работает ли это с иконками для JButtons? –

+0

@Anatoly Не могли бы вы поделиться больше ссылок на выше –

39

При загрузке ресурса убедитесь, что вы обратите внимание на разницу между:

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

и

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

Я думаю, эта путаница вызывает большинство проблем при загрузке ресурса. Когда вы загружаете изображение это проще использовать getResourceAsStream():

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

Когда вы действительно должны загрузить файл (без изображения) из архива JAR, вы можете попробовать это:

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 Это сработало для меня. Убедитесь, что вы помещаете файлы, которые хотите прочитать в папку «bin», и переходите в каталог загрузки классов в ресурсы перед использованием пути '/com/myorg/filename.ext '. – rayryeng

+0

+1 Это также работает для меня ... Я понимаю, что могут возникнуть некоторые риски безопасности, связанные с этим подходом, поэтому владельцы приложений должны знать об этом. – LucasA

+0

Вы могли бы прояснить это утверждение «Всегда лучше загружать ресурс с помощью getResourceAsStream()»? Как это может помочь решить проблему? –

0

Когда в файле jar ресурс находится абсолютно в иерархии пакетов (а не в иерархии файловой системы). Поэтому, если у вас есть класс com.example.Sweet, загружающий ресурс с именем «./default.conf», имя ресурса указывается как «/com/example/default.conf».

Но если это в банке, то это не файл ...

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

//Method Body 


InputStream invalidCharacterInputStream = URLClassLoader.getSystemResourceAsStream(FILE_LOCATION); 

Получение этого из getSystemResourceAsStream является лучшим вариантом. Получая входной поток, а не файл или URL-адрес, работает в JAR-файле и является автономным.

15

Одна линия ответ -

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

В основном getResource метод дает URL. Из этого URL вы можете извлечь путь, вызвав toExternalForm()

Ссылки:

getResource(), toExternalForm()

+1

При запуске из моей среды (IntelliJ) это создает простой URL-адрес файла, который работает во всех случаях. Однако при запуске из самого баннера я получаю URI, подобный jar: file: /path/to/jar/jarname.jar! /file_in_jar.mp4. Не все может использовать URI, который начинается с jar. Случай в точке JavaFX Media. –

+1

Мне больше нравится этот ответ. в большинстве случаев может быть предпочтительнее просто захватить InputStream для ресурса, когда он находится в файле jar, но если по какой-то причине вам действительно нужен путь, это то, что работает. Мне нужен был путь к стороннему объекту . Так что спасибо! – Mario

2

Это тот же код из пользовательского Tombart с потоком флеша и близко, чтобы избежать неполной временного содержания файла копии с jar и иметь уникальные имена файлов temp.

 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

В моем случае я использовал объект URL вместо Path.

Файл

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

ресурса в пути к классам с помощью загрузчика классов

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

Когда мне нужно прочитать содержимое, можно использовать следующий код:

InputStream stream = url.openStream(); 

А также вы можете получить доступ к содержимому с помощью InputStream.

0

Внутри ваши Ressources папка (Java/основные/ресурсов) ваша баночки добавить свой файл (мы предполагаем, что вы добавили файл XML с именем imports.xml), после чего вы впрыснуть ResourceLoader если вы используете весной как пыльник

@Autowired 
private ResourceLoader resourceLoader; 

внутри функции экскурсионном написать сильфона код для загрузки файла:

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