pigasus pigasus - 2 months ago 6
Java Question

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

I'm writing a program that is required to save a project in a chosen directory. Every project directory must include an HTML file, which may have varying elements depending on the state of the project, along with a standard library of JavaScript files in a sub-directory.

I'm not familiar with the means by which this would usually be accomplished in Java (or even how it could be accomplished in theory). Is there a particular tool, technique or library out there that would be suited to this task? Note that I'm using Eclipse as my IDE. I've been thinking about generating the files required using templates of some kind, and/or extracting them from a package, but I'm very new to this kind of problem and am not sure how to proceed from here.

EDIT: Elaborating further

My project is a small utility for my personal use, so maintainability won't be much of an issue. I'm using Java 8. Within each user created project there will only be three unchanging .js files in the library and a small html file that will be launched in a browser to run the scripts, along with a user generated .js file. Very basic stuff.

EDIT: Problem solved... I think

I've come up with my own partial solution, and I think I can figure the rest out from here, but D.B.'s post was still informative and helpful, so I'm accepting it as the answer.

I realize that my original question wasn't specific enough. I was hoping to hide my static script resources and the template for the HTML file so that they could not be directly accessible from the file system. I had been considering placing them within some kind of package file that would reside in the same directory as the application jar. It slipped my mind, however, that I could simply place them in a resource folder within the jar itself.

Creating the libraries directory within the user specified project directory:

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");


the unpackLibrary function:

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();
}
}


The application will work with a project in a temporary directory until the user decides to save it, in which case I will use D.B.'s suggestions to copy the project files to the new directory.

Answer

How you proceed is entirely up to you and your project requirements. It really depends on what these files are going to be used for, how they will be maintained, etc. Using templates would seem to be a good solution since then you can simply replace variables/tokens in the template when generating a new set of project files. Whether or not those templates are somehow packaged/zipped is again up to you. If you have a good reason to package or zip them then do so, if not then there's really no reason they would need to be.

If you do use templates the basic technique would be: read the template, process the template by replacing variables/tokens with values, write the resulting data to a new file.

If you're using Java 1.7 or higher take a look at the java.nio package and the tutorial for Java file I/O featuring NIO as it's very good and will help you to understand the API and how to use it to manipulate files.

Hope this helps to get you started.

EDIT -- Here is the update I promised in my comment:

As I understand it the program must copy a set of static files into a new directory. Since you have a "project" concept going on I don't think that the code should replace existing files, so if the project files already exist this program will fail out.

Assumptions:

  1. The static template files will reside in a folder that exists inside the current working directory for the application jar file. That is, if your executable jar lives in the folder C:\MyProgram (assuming a Windows file system) then your templates will exist in a folder within that folder - C:\MyProgram\templates for example.
  2. The program should create the entire directory tree structure up to and including the "project" folder.

Here is the code:

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;
    }
}