Как скопировать папку из ресурсов из jar как во время выполнения, так и в dev-env?

В настоящее время я делаю игру с заранее подготовленными уровнями, и сейчас я храню их в ресурсах. Мне нужно решение, как я могу извлечь папку из банки в среде производства и разработки.

Я попытался скопировать папку с помощью данного метода ниже и передать src в качестве File defaultWorld = new File(GameData.class.getClassLoader().getResource("worlds/").getFile()); и назначение как private static File worldsDir = new File("run/worlds");

public static void copyFolder(File src, File dest) {
    try {
        if (src.isDirectory()) {
            if (!dest.exists()) {
                dest.mkdir();
            }
            String[] files = src.list();

            for (String file : files) {
                copyFolder(new File(src, file), new File(dest, file));
            }
        } else {
            try (InputStream in = new FileInputStream(src)) {
                try (OutputStream out = new FileOutputStream(dest)) {
                    byte[] buffer = new byte[1024];
                    int length;
                    //copy the file content in bytes
                    while ((length = in.read(buffer)) > 0) {
                        out.write(buffer, 0, length);
                    }
                }
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Я ожидал, что вышеупомянутый метод будет работать как на dev, так и на рабочей среде, но он вызывает FileNotFoundException при открытии потока вывода файла.

Всего 2 ответа


Вы не можете перечислить ресурсы в банке.

Любые обходные пути, о которых вы думаете, ненадежны.

  • Никогда не вызывайте метод URL getFile() . Он не возвращает правильное имя файла; он просто возвращает путь и части запроса URL-адреса, с любым процентным выходом без изменений. Кроме того, jar-записи не являются file: URL-адресами, поэтому путь к ресурсу никогда не может быть действительным именем файла, когда он ссылается на jar-запись.
  • Единственный способ перечислить вещи в файле jar - это перебрать все записи jar, но вам даже не гарантирован доступ к вашему jar, потому что ClassLoaders не гарантированно является URLClassLoaders и, как правило, не гарантирует использование jar: URL.
  • Вы даже не можете полагаться на MyApplication.class.getProtectionDomain (). GetCodeSource (), потому что getCodeSource () может возвращать ноль.

Если вы хотите скопировать несколько файлов из вашего jar, вот несколько надежных способов сделать это:

  • Жесткий код списка ресурсов, которые вы планируете скопировать. Это ваше приложение, так что вы знаете, какие файлы вы помещаете в банку.
  • Держите в своем банке один текстовый файл со списком путей к ресурсам для копирования.
  • Сохраните ваши ресурсы в одном zip-архиве, который встроен в ваш jar-файл, и извлеките его самостоятельно с помощью ZipInputStream, который оборачивает MyApplication.class.getResourceAsStream.

Почему вы пытаетесь реализовать метод для копирования всего каталога в другой, если уже существует реализация для этого в Apache Commons IO?

FileUtils.copyDirectory(File src, File dst);

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

public void extractResourceFromJar(String resource, String dstPath) {

    File destination = new File(dstPath);
    InputStream sourceStream = getClass().getResourceAsStream(resource);

    FileUtils.copyInputStreamToFile(sourceStream, destination);

}

Источники: https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/FileUtils.html.


Есть идеи?

10000