在Java中以编程方式创建资源/源文件夹中的文件?

26

我有两个资源文件夹。

src - 这里是我的 .java 文件

resources - 这里是我的资源文件(图片、.properties),按文件夹(包)组织。

是否有一种方法可以通过编程方式在那个 resources 文件夹中添加另一个 .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");
但是它在文件系统中查找该路径。我如何强制它查找资源文件夹?编辑:让我解释一下。我有一个GUI应用程序,支持2种语言(资源文件夹中的2个.properties文件)。现在我添加了一个选项,用户可以轻松翻译应用程序,当他完成后,我将保存新的.properties文件在某个隐藏文件夹中,并从那里读取。但我希望我能将这些新的.properties文件(新语言)保存在当前语言旁边(资源文件夹),我有一个静态的Messages类,知道如何从磁盘和默认的资源文件夹中加载资源。但如果用户将此.jar文件带到其他机器上,他将没有那些新语言,因为它们在那台计算机上的磁盘上,而不在.jar文件内部。
6个回答

12

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-classestarget/classes中。


8
如果我想在 src/main/resources 目录中创建文件或文件夹而不是 /target/...,我该怎么做? - Soroush Shemshadi
第一行抛出异常,因为 : 是无效字符。 - user1803551

10
如其他人所述,资源是通过ClassLoader获得的。然而,当前两个答案未强调以下几点:
- ClassLoader旨在抽象出获取类和其他资源的过程。资源不必是文件系统中的文件;它可以是远程URL,也可以是您或其他人通过扩展java.lang.ClassLoader实现的任何内容。 - ClassLoader存在于子/父委托链中。 ClassLoader的正常行为是首先尝试从父级获取资源,然后才搜索自己的资源-但某些类加载器会执行相反的顺序(例如,在servlet容器中)。无论如何,您都需要确定要将内容放入哪个类加载器的位置,并且即使是上面或下面的另一个类加载器也可能“窃取”客户端代码的资源请求。 - 如Lionel Port所指出的那样,即使单个ClassLoader也可能具有多个加载位置。 - ClassLoader用于加载类。如果程序可以将文件写入类加载的位置,这很容易成为安全风险,因为用户可能会将代码注入到正在运行的应用程序中。
简短版:不要这样做。编写更抽象的界面以表示“我可以从中获取东西的资源库”,并为“我可以从中获取东西的资源库并添加东西”的概念创建子接口。以一种既使用ClassLoader.getContextClassLoader().getResource()(搜索类路径),又使用其他某种机制获取程序可能已从某个位置添加的内容的方式来实现后者。

@sacundim,我编辑了我的问题,因为评论太长了。 - vale4674

1
问题在于类路径可能包含多个根目录,因此在没有现有文件或目录的情况下区分要存储哪一个将会很困难。
如果您已经加载了现有文件。
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");

@ Lionel Port 我尝试了这个组合,但它不起作用。 URL url = FilesUtil.class.getResource("/messages/messages.properties"); System.out.println(url); File file = new File(url.toURI()); System.out.println(file);第一个输出给我磁盘上的绝对路径,但当我尝试从中创建文件时,它会抛出一个“java.lang.IllegalArgumentException: URI has an authority component”的异常。看起来Java无法在其工作区(.jar文件)内写入。 - vale4674
是的,它只能在你拥有写权限的扩展目录中工作。抱歉,我没有意识到你正在尝试更新jar文件。 - Lionel Port
可以简化为:new File(parentDirectoryUrl.getFile()) - Ducaz035

1
将编译后的子文件夹(“/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;
}
}

0

基于以下代码,您可以获取或创建一个文件并将其用作实用方法。

public static File getFileFromResource(String filePath) {
    ClassLoader classloader = Thread.currentThread().getContextClassLoader();
    return new File(Objects.requireNonNull(classloader.getResource(filePath)).getFile());
}

项目结构

您应该指定文件或文件夹的相对路径。使用方法:

getFileFromResource("application.properties");

输出: 文件路径为C:\Users\????\IdeaProjects\back-end\target\classes\application.properties

0
以下代码会写入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 目录的想法!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接