Create file in resources/source folder in java pro

2019-04-20 13:45发布

I have two resources folders.

src - here are my .java files

resources - here are my resources files (images, .properties) organized in folders (packages).

Is there a way to programmatically add another .properties file in that resources folder?

I tried something like this:

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

and before that created:

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

But it looks for that path on the file system. How can I force it to look in the resources folder?

EDIT: Let me say what is it about. I have a GUI application and I support 2 languages (2 .properties files in resources folder). Now I added a option that user can easily translate application and when he finishes I save that new .properties on a disk in some hidden folder and read it from there. But I was hoping I could save that new .properties files (new language) next to the current languages (resources folder). I have a static Messages class which knows how to load resources both from the disk and both the default ones in resources folder. But if user takes this .jar file on some other machine, he would't have that new languages since they are on disk on that computer, not inside .jar file.

5条回答
疯言疯语
2楼-- · 2019-04-20 14:06

Resources are loaded through a class loader, and the default class loader caches heavily.

You need your own class loader with the behaviour you need, to read resources from a non-static file system.

查看更多
来,给爷笑一个
3楼-- · 2019-04-20 14:12

As other people have mentioned, resources are obtained through a ClassLoader. What the two current responses have failed to stress, however, is these points:

  • ClassLoaders are meant to abstract the process of obtaining classes and other resources. A resource does not have to be a file in a filesystem; it can be a remote URL, or anything at all that you or somebody else might implement by extending java.lang.ClassLoader.
  • ClassLoaders exist in a child/parent delegation chain. The normal behavior for a ClassLoader is to first attempt to obtain the resource from the parent, and only then search its own resources—but some classloaders do the opposite order (e.g., in servlet containers). In any case, you'd need to identify which classloader's place for getting stuff you'd want to put stuff into, and even then another classloader above or below it might "steal" your client code's resource requests.
  • As Lionel Port points out, even a single ClassLoader may have multiple locations from which it loads stuff.
  • ClassLoaders are used to, well, load classes. If your program can write files to a location where classes are loaded from, this can easily become a security risk, because it might be possible for a user to inject code into your running application.

Short version: don't do it. Write a more abstract interface for the concept of "repository of resource-like stuff that I can get stuff from," and subinterface for "repository of resource-like stuff that I can get stuff from, but also add stuff from." Implement the latter in a way that both uses ClassLoader.getContextClassLoader().getResource() (to search the classpath) and, if that fails, uses some other mechanism to get stuff that the program may have added from some location.

查看更多
等我变得足够好
4楼-- · 2019-04-20 14:14

The following code writes into the classes directory, along with the class files.

As others have noted, beware of overwriting class files. Best to put your new files into a separate directory; however, that directory needs to already exist. To create it, create a sub-directory within the resources in the source, perhaps containing an empty file. For example 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();
    }
}

This does the trick, but I'd be nervous about deploying this outside of a strictly controlled environment. I don't really like the idea of unauthorised persons writing to my classes directory!

查看更多
Melony?
5楼-- · 2019-04-20 14:16

Problem would be the classpath can contain multiple root directories so distinguishing which one to store would be hard without an existing file or directory.

If you have an existing file loaded.

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

Otherwise try an get a handle on a directory you know is unique in your resources directory. (Not sure if this works)

URL url = this.getClass().getResource("/parentDirectory");
File parentDirectory = new File(new URI(url.toString()));
new File(parentDirectory, "newProperties.properties");
查看更多
男人必须洒脱
6楼-- · 2019-04-20 14:16

Cut the main project folder of the compiled subfolders ("/target/classes", "target/test-classes") and you have the basic path to reconstruct your project folders with:

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;
}
}
查看更多
登录 后发表回答