Search code examples
javafile-ionio2

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?


Solution

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