CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-codehaus-groovy--groovy-nio

NIO extensions for Apache Groovy providing enhanced file system operations and path handling

Pending
Overview
Eval results
Files

directory-operations.mddocs/

Directory Operations

Traverse directory structures with filtering, sorting, and recursion options. Support for file type filtering, name matching, and advanced traversal patterns with comprehensive closure-based processing.

Capabilities

Basic Directory Iteration

Iterate through files and directories in a directory with type filtering.

/**
 * Invokes the closure for each 'child' file in this 'parent' folder/directory.
 * Both regular files and subfolders/subdirectories are processed
 * @param self a Path (that happens to be a folder/directory)
 * @param closure a closure (the parameter is the Path for the 'child' file)
 * @throws FileNotFoundException if the given directory does not exist
 * @throws IllegalArgumentException if the provided Path object does not represent a directory
 */
void eachFile(Path self, Closure closure);

/**
 * Invokes the closure for each 'child' file in this 'parent' folder/directory.
 * Both regular files and subfolders/subdirectories can be processed depending on the fileType enum value
 * @param self a Path (that happens to be a folder/directory)
 * @param fileType if normal files or directories or both should be processed
 * @param closure the closure to invoke
 * @throws FileNotFoundException if the given directory does not exist
 * @throws IllegalArgumentException if the provided Path object does not represent a directory
 */
void eachFile(Path self, FileType fileType, Closure closure);

/**
 * Invokes the closure for each subdirectory in this directory, ignoring regular files
 * @param self a Path (that happens to be a folder/directory)
 * @param closure a closure (the parameter is the Path for the subdirectory file)
 * @throws FileNotFoundException if the given directory does not exist
 * @throws IllegalArgumentException if the provided Path object does not represent a directory
 */
void eachDir(Path self, Closure closure);

Usage Examples:

import java.nio.file.Path
import java.nio.file.Paths
import groovy.io.FileType

Path directory = Paths.get("/home/user/documents")

// Process all files and directories
directory.eachFile { file ->
    println "${file.fileName} - ${Files.isDirectory(file) ? 'DIR' : 'FILE'}"
}

// Process only regular files
directory.eachFile(FileType.FILES) { file ->
    println "File: ${file.fileName} (${file.size()} bytes)"
}

// Process only directories
directory.eachFile(FileType.DIRECTORIES) { dir ->
    println "Directory: ${dir.fileName}"
}
// or use the convenience method
directory.eachDir { dir ->
    println "Directory: ${dir.fileName}"
}

// Process with file type checking
directory.eachFile { path ->
    if (Files.isRegularFile(path)) {
        println "File: ${path.fileName}"
    } else if (Files.isDirectory(path)) {
        println "Directory: ${path.fileName}/"
    }
}

Recursive Directory Traversal

Recursively traverse directory trees with type filtering and processing options.

/**
 * Processes each descendant file in this directory and any sub-directories.
 * Processing consists of calling closure passing it the current file (which may be a normal file or subdirectory)
 * and then if a subdirectory was encountered, recursively processing the subdirectory
 * @param self a Path (that happens to be a folder/directory)
 * @param closure a Closure
 * @throws FileNotFoundException if the given directory does not exist
 * @throws IllegalArgumentException if the provided Path object does not represent a directory
 */
void eachFileRecurse(Path self, Closure closure);

/**
 * Processes each descendant file in this directory and any sub-directories.
 * Processing consists of potentially calling closure passing it the current file and then if a subdirectory was encountered,
 * recursively processing the subdirectory. Whether the closure is called is determined by whether
 * the file was a normal file or subdirectory and the value of fileType
 * @param self a Path (that happens to be a folder/directory)
 * @param fileType if normal files or directories or both should be processed
 * @param closure the closure to invoke on each file
 * @throws FileNotFoundException if the given directory does not exist
 * @throws IllegalArgumentException if the provided Path object does not represent a directory
 */
void eachFileRecurse(Path self, FileType fileType, Closure closure);

/**
 * Recursively processes each descendant subdirectory in this directory.
 * Processing consists of calling closure passing it the current subdirectory and then recursively processing that subdirectory.
 * Regular files are ignored during traversal
 * @param self a Path (that happens to be a folder/directory)
 * @param closure a closure
 * @throws FileNotFoundException if the given directory does not exist
 * @throws IllegalArgumentException if the provided Path object does not represent a directory
 */
void eachDirRecurse(Path self, Closure closure);

Usage Examples:

import java.nio.file.Path
import java.nio.file.Paths
import groovy.io.FileType

Path rootDir = Paths.get("/project")

// Recursively process all files and directories
rootDir.eachFileRecurse { file ->
    println file.toString()
}

// Recursively process only regular files
rootDir.eachFileRecurse(FileType.FILES) { file ->
    if (file.fileName.toString().endsWith(".java")) {
        println "Java file: ${file}"
    }
}

// Recursively process only directories
rootDir.eachFileRecurse(FileType.DIRECTORIES) { dir ->
    println "Directory: ${dir}"
}
// or use the convenience method
rootDir.eachDirRecurse { dir ->
    println "Directory: ${dir}"
}

// Count files by extension
Map<String, Integer> extensionCounts = [:]
rootDir.eachFileRecurse(FileType.FILES) { file ->
    String filename = file.fileName.toString()
    int lastDot = filename.lastIndexOf('.')
    String extension = lastDot > 0 ? filename.substring(lastDot) : "(no extension)"
    extensionCounts[extension] = (extensionCounts[extension] ?: 0) + 1
}
extensionCounts.each { ext, count ->
    println "${ext}: ${count} files"
}

Advanced Directory Traversal

Advanced traversal with extensive configuration options including filtering, sorting, depth control, and pre/post processing.

/**
 * Processes each descendant file in this directory and any sub-directories.
 * Convenience method for traverse(Path, Map, Closure) when no options to alter the traversal behavior are required
 * @param self a Path (that happens to be a folder/directory)
 * @param closure the Closure to invoke on each file/directory and optionally returning a FileVisitResult value
 *                which can be used to control subsequent processing
 * @throws FileNotFoundException if the given directory does not exist
 * @throws IllegalArgumentException if the provided Path object does not represent a directory
 */
void traverse(Path self, Closure closure);

/**
 * Processes each descendant file in this directory and any sub-directories.
 * The traversal can be adapted by providing various options in the options Map
 * @param self a Path (that happens to be a folder/directory)
 * @param options a Map of options to alter the traversal behavior
 * @param closure the Closure to invoke on each file/directory and optionally returning a FileVisitResult value
 *                which can be used to control subsequent processing
 * @throws FileNotFoundException if the given directory does not exist
 * @throws IllegalArgumentException if the provided Path object does not represent a directory or illegal filter combinations are supplied
 */
void traverse(Path self, Map<String, Object> options, Closure closure);

/**
 * Invokes the closure specified with key 'visit' in the options Map
 * for each descendant file in this directory tree. Convenience method
 * for traverse(Path, Map, Closure) allowing the 'visit' closure
 * to be included in the options Map rather than as a parameter
 * @param self a Path (that happens to be a folder/directory)
 * @param options a Map of options to alter the traversal behavior
 * @throws FileNotFoundException if the given directory does not exist
 * @throws IllegalArgumentException if the provided Path object does not represent a directory or illegal filter combinations are supplied
 */
void traverse(Path self, Map<String, Object> options);

Traversal Options:

  • type: A FileType enum to determine if normal files or directories or both are processed
  • preDir: A closure run before each directory is processed, optionally returning a FileVisitResult value
  • preRoot: A boolean indicating that the 'preDir' closure should be applied at the root level
  • postDir: A closure run after each directory is processed, optionally returning a FileVisitResult value
  • postRoot: A boolean indicating that the 'postDir' closure should be applied at the root level
  • visitRoot: A boolean indicating that the given closure should be applied for the root dir
  • maxDepth: The maximum number of directory levels when recursing (default is -1 which means infinite, set to 0 for no recursion)
  • filter: A filter to perform on traversed files/directories. If set, only files/dirs which match are candidates for visiting
  • nameFilter: A filter to perform on the name of traversed files/directories. If set, only files/dirs which match are candidates for visiting. (Must not be set if 'filter' is set)
  • excludeFilter: A filter to perform on traversed files/directories. If set, any candidates which match won't be visited
  • excludeNameFilter: A filter to perform on the names of traversed files/directories. If set, any candidates which match won't be visited. (Must not be set if 'excludeFilter' is set)
  • sort: A closure which if set causes the files and subdirectories for each directory to be processed in sorted order

Usage Examples:

import java.nio.file.Path
import java.nio.file.Paths
import groovy.io.FileType
import groovy.io.FileVisitResult

Path projectDir = Paths.get("/project")

// Simple traversal
projectDir.traverse { file ->
    println file.toString()
}

// Advanced traversal with options
def totalSize = 0
def count = 0

projectDir.traverse([
    type: FileType.FILES,
    nameFilter: ~/.*\.groovy$/,
    maxDepth: 3,
    preDir: { dir ->
        println "Entering directory: ${dir.fileName}"
        if (dir.fileName.toString() == '.git') {
            return FileVisitResult.SKIP_SUBTREE
        }
    },
    postDir: { dir ->
        println "Exiting directory: ${dir.fileName}"
    },
    sort: { a, b ->
        // Sort by type (directories first), then by name
        if (Files.isDirectory(a) != Files.isDirectory(b)) {
            return Files.isDirectory(a) ? -1 : 1
        }
        return a.fileName.toString().compareTo(b.fileName.toString())
    }
]) { file ->
    totalSize += file.size()
    count++
    println "Groovy file: ${file} (${file.size()} bytes)"
}

println "Found ${count} Groovy files totaling ${totalSize} bytes"

// Using visit closure in options
projectDir.traverse([
    type: FileType.FILES,
    excludeNameFilter: ~/\.(class|jar)$/,
    visit: { file ->
        println "Processing: ${file}"
    }
])

// Control traversal flow with FileVisitResult
projectDir.traverse([
    type: FileType.FILES,
    nameFilter: ~/.*\.txt$/
]) { file ->
    if (file.size() > 1024 * 1024) { // Files larger than 1MB
        println "Large file found: ${file}"
        return FileVisitResult.TERMINATE // Stop traversal
    }
    println "Text file: ${file}"
    return FileVisitResult.CONTINUE
}

File Name Matching

Match files and directories based on name patterns with various filtering options.

/**
 * Invokes the closure for each file whose name matches the given nameFilter in the given directory
 * Both regular files and subdirectories are matched
 * @param self a Path (that happens to be a folder/directory)
 * @param nameFilter the nameFilter to perform on the name of the file
 * @param closure the closure to invoke
 * @throws FileNotFoundException if the given directory does not exist
 * @throws IllegalArgumentException if the provided Path object does not represent a directory
 */
void eachFileMatch(Path self, Object nameFilter, Closure closure);

/**
 * Invokes the closure for each file whose name matches the given nameFilter in the given directory
 * Both regular files and subdirectories may be candidates for matching depending on the value of fileType
 * @param self a Path (that happens to be a folder/directory)
 * @param fileType whether normal files or directories or both should be processed
 * @param nameFilter the filter to perform on the name of the file/directory
 * @param closure the closure to invoke
 * @throws FileNotFoundException if the given directory does not exist
 * @throws IllegalArgumentException if the provided Path object does not represent a directory
 */
void eachFileMatch(Path self, FileType fileType, Object nameFilter, Closure closure);

/**
 * Invokes the closure for each subdirectory whose name matches the given nameFilter in the given directory
 * Only subdirectories are matched; regular files are ignored
 * @param self a Path (that happens to be a folder/directory)
 * @param nameFilter the nameFilter to perform on the name of the directory
 * @param closure the closure to invoke
 * @throws FileNotFoundException if the given directory does not exist
 * @throws IllegalArgumentException if the provided Path object does not represent a directory
 */
void eachDirMatch(Path self, Object nameFilter, Closure closure);

Usage Examples:

import java.nio.file.Path
import java.nio.file.Paths
import groovy.io.FileType

Path directory = Paths.get("/project/src")

// Match files with regex pattern
directory.eachFileMatch(~/.*\.java$/) { file ->
    println "Java file: ${file.fileName}"
}

// Match only directories with pattern
directory.eachFileMatch(FileType.DIRECTORIES, ~/test.*/) { dir ->
    println "Test directory: ${dir.fileName}"
}

// Use convenience method for directories
directory.eachDirMatch(~/lib.*/) { dir ->
    println "Library directory: ${dir.fileName}"
}

// Match with closure filter
directory.eachFileMatch({ fileName ->
    fileName.length() > 10 && fileName.endsWith(".groovy")
}) { file ->
    println "Long Groovy file: ${file.fileName}"
}

// Complex pattern matching
directory.eachFileMatch(FileType.FILES, ~/.*\.(java|groovy|scala)$/) { file ->
    def lang = file.fileName.toString().split('\\.').last()
    println "${lang.toUpperCase()} source: ${file.fileName}"
}

// Match backup files for deletion
directory.eachFileMatch(~/.*\.bak$/) { backup ->
    println "Deleting backup: ${backup.fileName}"
    Files.delete(backup)
}

Directory Management

Operations for managing directories including deletion and renaming.

/**
 * Deletes a directory with all contained files and subdirectories
 * @param self a Path
 * @return true if the file doesn't exist or deletion was successful, false otherwise
 */
boolean deleteDir(Path self);

/**
 * Renames a file
 * @param self a Path
 * @param newPathName The new pathname for the named file
 * @return true if and only if the renaming succeeded; false otherwise
 */
boolean renameTo(Path self, String newPathName);

/**
 * Renames a file
 * @param self a Path
 * @param newPathName The new target path specified as a URI object
 * @return true if and only if the renaming succeeded; false otherwise
 */
boolean renameTo(Path self, URI newPathName);

Usage Examples:

import java.nio.file.Path
import java.nio.file.Paths

Path tempDir = Paths.get("/tmp/my-temp-dir")
Path oldName = Paths.get("/project/old-name")
Path targetDir = Paths.get("/project/archive")

// Delete directory and all contents
if (tempDir.deleteDir()) {
    println "Successfully deleted ${tempDir}"
} else {
    println "Failed to delete ${tempDir}"
}

// Rename directory
if (oldName.renameTo("/project/new-name")) {
    println "Successfully renamed directory"
}

// Rename using URI
URI newLocation = new URI("file:///project/renamed-dir")
if (oldName.renameTo(newLocation)) {
    println "Successfully moved to new location"
}

// Safe directory cleanup
Path backupDir = Paths.get("/backups/old")
if (Files.exists(backupDir)) {
    if (backupDir.deleteDir()) {
        println "Old backup directory cleaned up"
    } else {
        println "Warning: Could not delete backup directory"
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-codehaus-groovy--groovy-nio

docs

directory-operations.md

file-appending.md

file-io.md

index.md

line-processing.md

object-serialization.md

stream-operations.md

tile.json