如何创建包含特定文件副本的目录结构?

How can I create a directory structure that includes copies of particular files?

我正在编写一个程序,需要将项目保存在选定的目录中。每个项目目录都必须包含一个 HTML 文件,该文件可能具有不同的元素,具体取决于项目的状态,以及子目录中 Java 脚本文件的标准库。

我不熟悉在 Java 中通常会用什么方法来完成(甚至在理论上是如何完成的)。是否有适合这项任务的特定工具、技术或库?请注意,我使用 Eclipse 作为 IDE。我一直在考虑使用某种模板生成所需的文件,and/or 从包中提取它们,但我对这类问题还很陌生,不确定如何从这里开始。

编辑:进一步阐述

我的项目是供我个人使用的小型实用程序,因此可维护性不是什么大问题。我正在使用 Java 8。在每个用户创建的项目中,库中只有三个不变的 .js 文件和一个将在浏览器中启动到 运行 的小 html 文件脚本,以及用户生成的 .js 文件。非常基本的东西。

编辑:问题已解决...我认为

我已经提出了我自己的部分解决方案,我想我可以从这里找到其余的解决方案,但是 D.B. 的 post 仍然提供了信息和帮助,所以我我接受它作为答案。

我意识到我原来的问题不够具体。我希望隐藏我的静态脚本资源和 HTML 文件的模板,以便无法从文件系统直接访问它们。我一直在考虑将它们放在与应用程序 jar 位于同一目录中的某种包文件中。然而,我忘记了我可以简单地将它们放在 jar 本身的资源文件夹中。

正在用户指定的项目目录中创建库目录:

libraryDir = projectDir.resolve("libraries");
new File(libraryDir.toUri()).mkdirs(); // Create libraries directory

// Unpack library resources to project
unpackLibrary("file1.js");
unpackLibrary("file2.js");
unpackLibrary("file3.js");

unpackLibrary 函数:

private void unpackLibrary(String scriptName) {
    String resourcePath = "/libraries/" + scriptName;

    Path fileName = Paths.get(resourcePath).getFileName();
    try (InputStream in = getClass().getResourceAsStream(resourcePath);) {
        Files.copy(in, libraryDir.resolve(fileName));
    }
    catch (FileAlreadyExistsException e) {
        System.out.println("File unpack failed: File already exists (" + e.getFile() + ")");
    }
    catch (IOException e) {
        e.printStackTrace();
    }
}

应用程序将使用临时目录中的项目,直到用户决定保存它,在这种情况下,我将使用 D.B 的建议将项目文件复制到新目录。

如何进行完全取决于您和您的项目要求。这实际上取决于这些文件的用途、维护方式等。使用模板似乎是一个很好的解决方案,因为这样您就可以在生成新集时简单地替换模板中的 variables/tokens的项目文件。这些模板是否以某种方式 packaged/zipped 再次取决于您。如果您有充分的理由打包或压缩它们,那么就这样做,如果没有,那么就真的没有理由需要它们。

如果您使用模板,基本技术是:读取模板,通过用值替换 variables/tokens 来处理模板,将结果数据写入新文件。

如果您使用的是 Java 1.7 或更高版本,请查看 java.nio 软件包和 tutorial for Java file I/O featuring NIO,因为它非常好,可以帮助您理解 API 以及如何使用它来操作文件。

希望这有助于您入门。

编辑——这是我在评论中承诺的更新:

据我了解,该程序必须将一组静态文件复制到一个新目录中。因为你有一个 "project" 的概念,我不认为代码应该替换现有文件,所以如果项目文件已经存在,这个程序将失败。

假设:

  1. 静态模板文件将驻留在应用程序 jar 文件的当前工作目录中的文件夹中。也就是说,如果您的可执行 jar 位于文件夹 C:\MyProgram 中(假设一个 Windows 文件系统),那么您的模板将存在于该文件夹内的一个文件夹中 - 例如 C:\MyProgram\templates。
  2. 程序应创建整个目录树结构,包括 "project" 文件夹。

代码如下:

SaveProjectFolderMain.java

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class SaveProjectFolderMain {

    //Note: In eclipse your templates folder must be inside the eclipse project's root directory 
    //      in order for this path to be correct. E.g. myProject/templates
    //      If this program is run outside of eclipse it will look for a templates folder
    //      in the current working directory - the directory in which the jar resides.
    //      E.g. if you jar lives in C:\myProgram then your templates should live in
    //      C:\myProgram\templates (obviously this is a Windows file system example)
    private static final Path TEMPLATES_DIR = Paths.get("templates");

    public static void main(String[] args) {
        //Copies the template files to a new folder called "testProject"
        // creating the project folder if it does not exist.
        saveProjectDir(Paths.get("testProject"));
    }

    public static void saveProjectDir(Path dirToSaveTo){
        try {
            if(!Files.exists(dirToSaveTo)){
                System.out.println("The directory " + dirToSaveTo.toAbsolutePath() + " does not exist, it is being created.");
                Files.createDirectories(dirToSaveTo);
            }
            Files.walkFileTree(TEMPLATES_DIR, new CopyFileVisitor(dirToSaveTo));
        } catch (IOException e) {
            System.err.println("Unable to copy template files to the save location: " + dirToSaveTo.toAbsolutePath());
            e.printStackTrace();
        }
    }

}

CopyFileVisitor.java

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;

public class CopyFileVisitor extends SimpleFileVisitor<Path> {
    private final Path targetPath;
    private Path sourcePath = null;

    public CopyFileVisitor(Path targetPath) {
        this.targetPath = targetPath;
    }

    @Override
    public FileVisitResult preVisitDirectory(final Path dir,
            final BasicFileAttributes attrs) throws IOException {
        if (sourcePath == null) {
            sourcePath = dir;
        } else {
            Path destDir = targetPath.resolve(sourcePath.relativize(dir));
            System.out.println("Creating directory: " + destDir);
            Files.createDirectories(destDir);
        }
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult visitFile(final Path file,
            final BasicFileAttributes attrs) throws IOException {
        Path destFilePath = targetPath.resolve(sourcePath.relativize(file));
        System.out.println("Copying " + file.toAbsolutePath() + " to " + destFilePath.toAbsolutePath());
        Files.copy(file, destFilePath);
        return FileVisitResult.CONTINUE;
    }
}