Создать файл в папке ресурсов/исходного кода в Java программно?

У меня есть две папки ресурсов.

src - вот мои .java файлы

Ресурсы

- вот мои файлы ресурсов (изображения,.properties), организованные в папках (пакетах).

Есть ли способ программно добавить другой файл .properties в эту папку ресурсов?

Я пробовал что-то вроде этого:

public static void savePropertiesToFile(Properties properties, File propertiesFile) throws IOException {
        FileOutputStream out = new FileOutputStream(propertiesFile);
        properties.store(out, null);
        out.close();
    }

и до этого создан:

new File("/folderInResources/newProperties.properties");

Но он ищет этот путь в файловой системе. Как заставить его искать в папке ресурсов?

EDIT. Позвольте мне сказать, о чем это. У меня есть приложение с графическим интерфейсом, и я поддерживаю 2 языка (2 файла .properties в папке ресурсов). Теперь я добавил вариант, который пользователь может легко перевести приложение, и когда он закончит, я сохраню эти новые .properties на диске в какой-то скрытой папке и прочитал его оттуда. Но я надеялся, что смогу сохранить новые .properties файлы (новый язык) рядом с текущими языками (папками ресурсов). У меня есть статический класс сообщений, который знает, как загружать ресурсы как с диска, так и по умолчанию в папке ресурсов. Но если пользователь возьмет этот .jar файл на какой-либо другой машине, у него будут такие новые языки, поскольку они находятся на диске на этом компьютере, а не внутри .jar файла.

Ответ 1

Как отмечали другие люди, ресурсы получаются через ClassLoader. Однако эти два текущих ответа не смогли подчеркнуть следующие моменты:

  • ClassLoaders предназначены для абстрактного процесса получения классов и других ресурсов. Ресурс не обязательно должен быть файлом в файловой системе; это может быть удаленный URL-адрес или что-то еще, что вы или кто-то еще может реализовать, расширяя java.lang.ClassLoader.
  • ClassLoaders существуют в цепочке дочерних/родительских делегирования. Обычное поведение для ClassLoader состоит в том, чтобы сначала попытаться получить ресурс от родителя и только затем выполнить поиск его собственных ресурсов, но некоторые загрузчики классов выполняют противоположный порядок (например, в контейнерах сервлетов). В любом случае вам нужно будет определить, какой класс загрузчика для получения материала, в который вы хотите поместить материал, и даже тогда другой загрузчик классов выше или ниже может "украсть" ваши запросы ресурса кода клиента.
  • Как отмечает Lionel Port, даже один ClassLoader может иметь несколько местоположений, из которых он загружает вещи.
  • ClassLoaders используются для загрузки классов. Если ваша программа может записывать файлы в место, где загружаются классы, это может легко стать угрозой безопасности, поскольку пользователь может ввести код в ваше запущенное приложение.

Короткий вариант: не делайте этого. Напишите более абстрактный интерфейс для концепции "хранилища ресурсоподобных вещей, из которых я могу получить материал", и subinterface для "хранилища ресурсоподобных материалов, из которых я могу получить материал, а также добавить материал". Внедрите последнее так, чтобы в обоих случаях использовался ClassLoader.getContextClassLoader().getResource() (для поиска пути к классам), и если это не удается, используется другой механизм для получения информации, которую программа могла бы добавить из некоторого местоположения.

Ответ 2

Отредактируйте основную папку проекта скомпилированных подпапок ( "/target/classes", "target/test-classes" ), и у вас есть основной путь для восстановления папок проекта с помощью:

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;

public class SubfolderCreator {

public static void main(String... args) throws URISyntaxException, IOException {
    File newResourceFolder = createResourceSubFolder("newFolder");
}

private static File createResourceSubFolder(String folderName) throws URISyntaxException, IOException {
    java.net.URL url = SubfolderCreator.class.getResource("/EXISTING_SUBFOLDER/");
    File fullPathToSubfolder = new File(url.toURI()).getAbsoluteFile();
    String projectFolder = fullPathToSubfolder.getAbsolutePath().split("target")[0];
    File testResultsFolder = new File(projectFolder + "src/test/resources/" + folderName);
    if (!testResultsFolder.exists()) {
        testResultsFolder.mkdir();
    }
    return testResultsFolder;
}
}

Ответ 3

Решение Java 8

 Path source = Paths.get(this.getClass().getResource("/").getPath());
        Path newFolder = Paths.get(source.toAbsolutePath() + "/newFolder/");
        Files.createDirectories(newFolder);

Это обязательно создаст новую папку в папке ресурсов. но вы найдете новую папку в целевой среде выполнения.

который будет ProjectName/target/test-classes/newFolder. если вы запускаете этот код в тестовом примере. В противном случае это было бы в target/classes

Не пытайтесь найти новую папку в вашем src/resources. это будет обязательно в target/test-classes или target/classes.

Ответ 4

Ресурсы загружаются через загрузчик классов, а загрузчик классов по умолчанию сильно кэшируется.

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

Ответ 5

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

Если у вас уже загружен существующий файл.

File existingFile = ...;
File parentDirectory = existingFile.getParentFile();
new File(parentDirectory, "newProperties.properties");

В противном случае попробуйте получить дескриптор в каталоге, который, как вам известно, уникален в вашем каталоге ресурсов. (Не уверен, что это работает)

URL url = this.getClass().getResource("/parentDirectory");
File parentDirectory = new File(new URI(url.toString()));
new File(parentDirectory, "newProperties.properties");

Ответ 6

Следующий код записывается в каталог classes вместе с файлами классов.

Как отмечали другие, остерегайтесь перезаписывать файлы классов. Лучше всего поместить ваши новые файлы в отдельный каталог; однако этот каталог должен уже существовать. Чтобы создать его, создайте подкаталог в ресурсах источника, возможно, содержащий пустой файл. Например src\main\resources\dir\empty.txt.

public class WriteResource {
    public static void main(String[] args) throws FileNotFoundException {
        String thing = "Text to write to the file";
        String dir = WriteResource.class.getResource("/").getFile();
        //String dir = WriteResource.class.getResource("/dir").getFile();
        OutputStream os = new FileOutputStream(dir + "/file.txt");
        final PrintStream printStream = new PrintStream(os);
        printStream.println(thing);
        printStream.close();
    }
}

Это делает трюк, но я бы нервничал из-за развертывания этого вне строго контролируемой среды. Мне не очень нравится идея несанкционированного доступа к моей директории classes!