DirectoryStream.Filter example for listing files that based on certain date/time

I am trying to investigate a DirecoryStream.Filter example for newDirectoryStream where I can achieve to list all files under a directory(and all its sub directories) that are older than 60 days, as an example.

DirectoryStream<Path> dirS = Files.newDirectoryStream(Paths.get("C:/myRootDirectory"), <DirectoryStream.filter>);

for (Path entry: dirS) {
    System.out.println(entry.toString());
}

In the code above, what should be the DirectoryStream.filter? It will be a great help as I am in a project where I am trying to delete files older than a certain timestamp and pre-java 1.7 File.listFiles() just hangs.

Could Files.walkFileTree() provide an option?

Answers


If I get this right, you have 2 situations:

  1. Create a custom filter to select files older than 60 days
  2. Traverse through subdirectories (the entire FileTree) and gather your information

The custom filter is easier to implement with conditions of 60 days implemented using Calendar class:

DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
    @Override
    public boolean accept(Path entry) throws IOException {BasicFileAttributes attr = Files.readAttributes(entry,BasicFileAttributes.class);
    FileTime creationTime = attr.creationTime();
    Calendar cal = Calendar.getInstance();
    int days = cal.fieldDifference(new Date(creationTime.toMillis()),Calendar.DAY_OF_YEAR);
        return (Math.abs(days) > 60);
        }
  };

The normal execution would only look for the files in the root directory. To look for subdirectory, your guess of using walkFileTree() is right.

However, this requires an implementation of the FileVisitor interface, a simple implementation of which luckily is bundled with 7 - SimpleFileVisitor.

To traverse through the subdirectories, you can choose to override a directory specific method - I have used preVisitDirectory of SimpleFileVisitor here:

Files.walkFileTree(dirs, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path file,
                    BasicFileAttributes attrs) {

Since preVisitDirectory will be custom made to return FileVisitResult.CONTINUE; in case you don't have any additional restrictions, we would leverage preVisitDirectory method to iterate through our directory 1 at a time while applying the filter.

Files.walkFileTree(dirs, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path file,
                    BasicFileAttributes attrs) {

                DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
                    @Override
                    public boolean accept(Path entry) throws IOException {
                        BasicFileAttributes attr = Files.readAttributes(entry,
                                BasicFileAttributes.class);
                        FileTime creationTime = attr.creationTime();
                        Calendar cal = Calendar.getInstance();
                        int days = cal.fieldDifference(
                                new Date(creationTime.toMillis()),
                                Calendar.DAY_OF_YEAR);
                        return (Math.abs(days) > 60);
                    }
                };
                try (DirectoryStream<Path> stream = Files.newDirectoryStream(
                        file, filter)) {
                    for (Path path : stream) {
                        System.out.println(path.toString());
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                return FileVisitResult.CONTINUE;

            }
        }); 

This would give you the files from the entire directory and subdirectory structures for the required filter criteria, complete main method below:

public static void main(String[] args) throws IOException {
        Path dirs = Paths.get("C:/");

        Files.walkFileTree(dirs, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path file,
                    BasicFileAttributes attrs) {

                DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
                    @Override
                    public boolean accept(Path entry) throws IOException {
                        BasicFileAttributes attr = Files.readAttributes(entry,
                                BasicFileAttributes.class);
                        FileTime creationTime = attr.creationTime();
                        Calendar cal = Calendar.getInstance();
                        int days = cal.fieldDifference(
                                new Date(creationTime.toMillis()),
                                Calendar.DAY_OF_YEAR);
                        return (Math.abs(days) > 60);
                    }
                };
                try (DirectoryStream<Path> stream = Files.newDirectoryStream(
                        file, filter)) {
                    for (Path path : stream) {
                        System.out.println(path.toString());
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                return FileVisitResult.CONTINUE;

            }
        });

    }

Simply create a new DirectoryStream.Filter instance that returns true if the given Path object is older than 60 days.

DirectoryStream<Path> dirStream = Files.newDirectoryStream(Paths.get("/some/path"), new Filter<Path>() {
    @Override
    public boolean accept(Path entry) throws IOException {
        FileTime fileTime = Files.getLastModifiedTime(entry);
        long millis = fileTime.to(TimeUnit.MILLISECONDS);
        Calendar today = Calendar.getInstance();
        // L is necessary for the result to correctly be calculated as a long 
        return today.getTimeInMillis() > millis + (60L * 24 * 60 * 60 * 1000);
    }
});

Note that this will only give you the files inside the root of the specified directory Path, ie. the Path argument passed to newDirectoryStream(..).

If you want all files in sub directories as well, Files.walkFileTree(..) is probably easier to use. You'll just have to implement a FileVisitor that stores a List or Set of Path objects that you collect along the way using the same logic as the Filter above.


Need Your Help

Android - RelativeLayout CENTER_VERTICAL and BELOW issue

android center relativelayout

I want a TextView on top and a VideoView below it. I want to have the VideoView as center verical and below the TextView. I am using RelativeLayout.