开发者

Java copy a folder excluding some internal file

I have a folder with this structure

mainFolder

   --Sub1  
         --File .scl
         --File .awl
         --Other files
   --Sub2  
         --Files
   --Sub3
   --Sub4

I want to copy it to another location but i want the Sub3 to be avoided and (depending from the situation) some file from the Sub1

Here is an extract from what i did so 开发者_StackOverflow社区far:

FileUtils.copyDirectory(srcDir, dstDir, new FileFilter() {
        public boolean accept(File pathname) {
            // We don't want 'Sub3' folder to be imported
            // + look at the settings to decide if some format needs to be
            // excluded
            String[] ignoreList= new String[]{
                    !Settings.getSiemensOptionAWL() ? ".awl":"uselessStringWilNeverBeFound",
                    !Settings.getSiemensOptionSCL() ? ".scl":"uselessStringWilNeverBeFound",
                    "Sub3"
            };

            return !(ignoreFile(pathname, ignoreList) && pathname
                    .isDirectory());
        }
    }, true);


    public static boolean ignoreFile(File file, String[] ignoreList) {
        for (final String ignoreStr : ignoreList)
            if (file.getAbsolutePath().contains(ignoreStr))
                return true;
        return false;
    }

Apparently it seams to work. But i think is a very ugly solution.... Does anyone knows a better way?

P.S: of course Settings.getSiemensOptionAWL() is just boolean function taht return my decision


The other options suggested here are good, however another alternative is to nest multiple simpler FileFilters together (which may be overkill, of course!)

public class FailFastFileFilter implements FileFilter {
    protected final List<FileFilter> children = new ArrayList<FileFilter>();

    public FailFastFileFilter(FileFilter... filters) {
        for (FileFilter filter: filters) {
            if (filter != null)
                this.filters.add(filter);
        }       
    }

    public boolean accept(File pathname) {
        for (FileFilter filter: this.filters) {
            if (!filter.accept(pathname)) {
                return false; // fail on the first reject
            }
        }

        return true;
    }
}

Then simply combine short, concise FileFilters for the Sub3 case, the .scl and the .awl case. The example FailFastFileFilter I've shown above would let you specify null as one of the filters (so you could use inline if statements to determine whether particular FileFilters are applied)

For the sake of completion, here's a general idea of how I'd implement the child filters for the Sub1 cases and the Sub3 case.

First, a filter to excluding files with a particular extension within a directory:

public class ExcludeExtensionInDirFileFilter implements FileFilter {
    protected final String parentFolder;
    protected final String extension;

    public ExtensionFileFilter(String parentFolder, String extension) {
        this.parentFolder = parentFolder;
        this.extension = extension.toLowerCase();
    }

    public boolean accept(File file) {
        if (!file.isDirectory() && file.getParentFile().getName().equalsIgnoreCase(parentFolder))
            return !file.getAbsolutePath().toLowerCase().endsWith(extension);
        else
            return true;
    }
}

Then to exclude a directory:

public class ExcludeDirFileFilter implements FileFilter {
    protected final String name;

    public ExcludeDirFileFilter(String name) {
        this.name = name.toLowerCase();
    }

    public boolean accept(File file) {
        if (file.isDirectory() && file.getName().equalsIgnoreCase(name))
            return false;
        else
            return true;
    }
}

Setting up the FailFastFileFilter would then look something like:

FileFilter filters = new FailFastFileFilter(
    new ExcludeDirFileFilter("Sub3"), // always exclude Sub3
    (!Settings.getSiemensOptionAWL() ? new ExcludeExtensionInDirFileFilter("Sub1",".awl"), null), // Exclude Sub1/*.awl if desired
    (!Settings.getSiemensOptionSCL() ? new ExcludeExtensionInDirFileFilter("Sub1",".scl"), null) // Exclude Sub1/*.scl if desired
);

FileUtils.copyDirectory(srcDir, dstDir, filters);


I think the ugliness comes from introducing ignoreFile(), which necessarily loses some of the useful information (which strings actually matter, which strings are file extensions, etc.) Additionally, that array is going to be created for every file in your hierarchy, which is extremely inefficient. Consider something like this, instead:

FileUtils.copyDirectory(srcDir, dstDir, new FileFilter() {
    public boolean accept(File pathname) {
        // We don't want 'Sub3' folder to be imported
        // + look at the settings to decide if some format needs to be
        // excluded
        String name = pathname.getName();
        if (!Settings.getSiemensOptionAWL() && name.endsWith(".awl"))
            return false;
        if (!Settings.getSiemensOptionSCL() && name.endsWith(".scl"))
            return false;

        return !(name.equals("Sub3") && pathname.isDirectory());
    }
}, true);


Is the case of those string fixed in stone? Maybe something like

new FileFilter() {
    public boolean accept(File pathname) {
        String path = pathname.getAbsolutePath().toLowerCase();

        return (!pathname.isDirectory() || path.endsWith("sub3")) &&
            (!Settings.getSiemensOptionAWL() && path.endsWith(".awl")) &&
            (!Settings.getSiemensOptionSCL() && path.endsWith(".scl"));
    }
}


Looks pretty clean to me. Just don't put all that directly in the calling code so you don't have to look at it all the time. Make your own CopySubDir class that hides all this code and provides a simple to understand interface to it. Then the calling code will look clean.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜