Как получить путь к ресурсу в 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)

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

Ответ 1

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

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

Ответ 2

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

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.getProtocol().equals("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);
            }
            out.close();
            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!");
    }

Ответ 3

Ответ в одну строку -

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

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

Рекомендации:

getResource(), toExternalForm()

Ответ 4

Я провел некоторое время с этой проблемой, потому что никакое решение, которое я нашел, действительно работало, как ни странно! Рабочий каталог часто не является каталогом 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.
}

Ответ 5

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

Ответ 6

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

src/main/resources/myfile.txt

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

Ответ 7

Это тот же код от пользователя 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());
        }

Ответ 8

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

Файл

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

Ресурс в пути к классам с помощью classloader

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

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

InputStream stream = url.openStream();

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

Ответ 9

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

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

Ответ 10

Это, как было сказано, не является оптимальным способом загрузки ресурсов, но если вы абсолютно должны иметь ссылку 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.

Ответ 11

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

Ответ 12

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

//Method Body


InputStream invalidCharacterInputStream = URLClassLoader.getSystemResourceAsStream(FILE_LOCATION);

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

Ответ 13

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

@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();}

Ответ 14

Это может быть немного поздно, но вы можете использовать мою библиотеку KResourceLoader, чтобы получить ресурс из вашего jar:

File resource = getResource("file.txt")

Ответ 15

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

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

Ответ 16

Может быть, этот метод можно использовать для быстрого решения.

public class TestUtility
{ 
    public static File getInternalResource(String relativePath)
    {
        File resourceFile = null;
        URL location = TestUtility.class.getProtectionDomain().getCodeSource().getLocation();
        String codeLocation = location.toString();
        try{
            if (codeLocation.endsWith(".jar"){
                //Call from jar
                Path path = Paths.get(location.toURI()).resolve("../classes/" + relativePath).normalize();
                resourceFile = path.toFile();
            }else{
                //Call from IDE
                resourceFile = new File(TestUtility.class.getClassLoader().getResource(relativePath).getPath());
            }
        }catch(URISyntaxException ex){
            ex.printStackTrace();
        }
        return resourceFile;
    }
}