web-dev-qa-db-fra.com

Créer un fichier dans le dossier resources/source en Java par programme?

J'ai deux dossiers de ressources.

src - voici mes fichiers .Java

ressources - voici mes fichiers de ressources (images, .properties) organisés en dossiers (packages).

Existe-t-il un moyen d'ajouter par programme un autre fichier .properties dans ce dossier de ressources?

J'ai essayé quelque chose comme ça:

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

et avant que créé:

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

Mais il recherche ce chemin sur le système de fichiers. Comment puis-je le forcer à regarder dans le dossier des ressources?

EDIT: Laissez-moi vous dire de quoi il en retourne. J'ai une application graphique et je supporte 2 langues (2 fichiers .properties dans le dossier des ressources). Maintenant, j'ai ajouté une option permettant à l'utilisateur de traduire facilement une application. Une fois l'opération terminée, j'enregistre ce nouveau fichier .properties sur un disque situé dans un dossier caché, puis je le lis à partir de là. Mais j'espérais pouvoir enregistrer ces nouveaux fichiers .properties (nouvelle langue) à côté des langues actuelles (dossier de ressources). J'ai une classe statique de messages qui sait comment charger des ressources à la fois du disque et des valeurs par défaut dans le dossier des ressources. Mais si l'utilisateur prend ce fichier .jar sur une autre machine, il n'aura pas cette nouvelle langue puisqu'il se trouve sur le disque de cet ordinateur et non à l'intérieur du fichier .jar.

11
vale4674

Comme d'autres personnes l'ont mentionné, les ressources sont obtenues via un ClassLoader. Ce que les deux réponses actuelles ont toutefois omis de souligner, ce sont les points suivants:

  • Les ClassLoaders sont destinés à résumer le processus d'obtention de classes et d'autres ressources. Une ressource ne doit pas nécessairement être un fichier dans un système de fichiers; il peut s'agir d'une URL distante ou de tout autre élément que vous ou une autre personne pourriez implémenter en développant Java.lang.ClassLoader.
  • Les ClassLoaders existent dans une chaîne de délégation enfant/parent. Le comportement normal d'un ClassLoader consiste d'abord à tenter d'obtenir la ressource auprès du parent, puis à rechercher ses propres ressources, mais certains chargeurs de classe effectuent l'ordre inverse (par exemple, dans des conteneurs de servlet). Dans tous les cas, vous devez identifier l'emplacement du chargeur de classe dans lequel vous souhaitez insérer des éléments. Même dans ce cas, un autre chargeur de classe situé au-dessus ou au-dessous risque de "voler" les demandes de ressources de votre code client.
  • Comme le souligne Lionel Port, même un ClassLoader peut avoir plusieurs emplacements à partir duquel il charge des choses.
  • Les ClassLoaders sont habitués à charger des classes. Si votre programme peut écrire des fichiers dans un emplacement d'où sont chargées les classes, cela peut facilement devenir un risque pour la sécurité, car il pourrait être possible pour un utilisateur d'injecter du code dans votre application en cours d'exécution.

Version courte: ne le faites pas. Ecrivez une interface plus abstraite pour le concept de "référentiel d'éléments de type ressources dont je peux obtenir des éléments" et une sous-interface pour "un référentiel d'éléments de type ressources dont je peux obtenir des éléments, mais aussi ajouter des éléments". Implémentez ce dernier de manière à utiliser ClassLoader.getContextClassLoader().getResource() (pour rechercher dans le chemin de classe) et, en cas d'échec, à utiliser un autre mécanisme pour obtenir des éléments que le programme peut avoir ajoutés à partir d'un emplacement donné.

6
Luis Casillas

Coupez le dossier de projet principal des sous-dossiers compilés ("/ target/classes", "target/test-classes") et vous aurez le chemin de base pour reconstruire vos dossiers de projet avec:

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;
}
}
0
Emiel Ackermann

Le problème serait que le chemin de classe peut contenir plusieurs répertoires racine afin de distinguer celui à stocker serait difficile sans un fichier ou un répertoire existant.

Si vous avez un fichier existant chargé.

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

Sinon, essayez d'obtenir un identifiant sur un répertoire que vous savez être unique dans votre répertoire de ressources. (Pas sûr si cela fonctionne)

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

Le code suivant écrit dans le répertoire classes, avec les fichiers de classe.

Comme d'autres l'ont noté, méfiez-vous des fichiers de classe d'écrasement. Il est préférable de placer vos nouveaux fichiers dans un répertoire séparé. Cependant, ce répertoire doit déjà exister. Pour le créer, créez un sous-répertoire au sein des ressources de la source, contenant peut-être un fichier vide. Par exemple 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();
    }
}

Cela fait l'affaire, mais je serais inquiet de le déployer en dehors d'un environnement strictement contrôlé. Je n'aime pas trop l'idée que des personnes non autorisées écrivent dans mon répertoire classes!

0
Steve Pitchers

Les ressources sont chargées via un chargeur de classes et le chargeur de classes par défaut met fortement en cache.

Vous avez besoin de votre propre chargeur de classes avec le comportement dont vous avez besoin pour lire les ressources d'un système de fichiers non statique.

0