CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-kotlin--kotlin-stdlib-jdk7

Kotlin Standard Library JDK 7 extension providing Path utilities and platform-specific implementations for Java NIO and JDK 7+ features

Pending
Overview
Eval results
Files

tree-traversal.mddocs/

Tree Traversal Operations

Advanced directory tree traversal operations with walking sequences, customizable file visitor patterns, and comprehensive options for complex file system navigation and processing.

Capabilities

Path Walking

Traverse directory trees using lazy sequences with multiple traversal options.

/**
 * Returns a sequence of paths for visiting this directory and all its contents.
 * By default, the returned sequence includes only files in the file tree, in depth-first order.
 * @param options options to control walk behavior
 */
fun Path.walk(vararg options: PathWalkOption): Sequence<Path>

/**
 * An enumeration to provide walk options for the Path.walk function.
 */
@SinceKotlin("2.1")
enum class PathWalkOption {
    /** Includes directory paths in the resulting sequence of the walk */
    INCLUDE_DIRECTORIES,
    /** Walks in breadth-first order instead of depth-first */
    BREADTH_FIRST,
    /** Follows symbolic links to the directories they point to */
    FOLLOW_LINKS
}

Usage Examples:

import kotlin.io.path.*
import java.nio.file.Paths

val projectDir = Paths.get("/home/user/my-project")

// Basic walk - files only, depth-first
projectDir.walk().forEach { file ->
    println("File: ${file.relativeTo(projectDir)}")
}

// Include directories in the walk
projectDir.walk(PathWalkOption.INCLUDE_DIRECTORIES).forEach { path ->
    val type = if (path.isDirectory()) "DIR" else "FILE"
    println("$type: ${path.relativeTo(projectDir)}")
}

// Breadth-first traversal with directories
projectDir.walk(
    PathWalkOption.INCLUDE_DIRECTORIES,
    PathWalkOption.BREADTH_FIRST
).forEach { path ->
    val depth = path.relativeTo(projectDir).nameCount
    val indent = "  ".repeat(depth)
    println("$indent${path.name}")
}

// Follow symbolic links (be careful of cycles)
try {
    projectDir.walk(PathWalkOption.FOLLOW_LINKS).forEach { file ->
        println("File (following links): ${file.relativeTo(projectDir)}")
    }
} catch (e: java.nio.file.FileSystemLoopException) {
    println("Detected symbolic link loop: ${e.message}")
}

// Filter and process specific files
val kotlinFiles = projectDir.walk()
    .filter { it.extension == "kt" }
    .toList()

println("Found ${kotlinFiles.size} Kotlin files")

// Count files by extension
val filesByExtension = projectDir.walk()
    .groupBy { it.extension }
    .mapValues { (_, files) -> files.size }

filesByExtension.forEach { (ext, count) ->
    val extension = if (ext.isEmpty()) "(no extension)" else ext
    println(".$extension: $count files")
}

File Visitor Pattern

Use the visitor pattern for complex file tree operations with precise control over traversal behavior.

/**
 * Visits this directory and all its contents with the specified visitor.
 * The traversal is in depth-first order and starts at this directory.
 */
fun Path.visitFileTree(
    visitor: FileVisitor<Path>, 
    maxDepth: Int = Int.MAX_VALUE, 
    followLinks: Boolean = false
)

/**
 * Visits this directory and all its contents with the FileVisitor defined in builderAction.
 */
fun Path.visitFileTree(
    maxDepth: Int = Int.MAX_VALUE,
    followLinks: Boolean = false,
    builderAction: FileVisitorBuilder.() -> Unit
)

/**
 * Builds a FileVisitor whose implementation is defined in builderAction.
 */
fun fileVisitor(builderAction: FileVisitorBuilder.() -> Unit): FileVisitor<Path>

Usage Examples:

import kotlin.io.path.*
import java.nio.file.*
import java.nio.file.attribute.BasicFileAttributes

val projectDir = Paths.get("/home/user/project")

// Clean build artifacts using file visitor
val cleanVisitor = fileVisitor {
    onPreVisitDirectory { directory, _ ->
        when (directory.name) {
            "build", "target", ".gradle", "node_modules" -> {
                println("Cleaning: ${directory.relativeTo(projectDir)}")
                directory.deleteRecursively()
                FileVisitResult.SKIP_SUBTREE
            }
            else -> FileVisitResult.CONTINUE
        }
    }
    
    onVisitFile { file, _ ->
        when (file.extension) {
            "class", "o", "obj", "pyc" -> {
                println("Removing: ${file.relativeTo(projectDir)}")
                file.deleteIfExists()
            }
        }
        FileVisitResult.CONTINUE
    }
    
    onVisitFileFailed { file, exception ->
        println("Failed to visit ${file.relativeTo(projectDir)}: ${exception.message}")
        FileVisitResult.CONTINUE
    }
}

projectDir.visitFileTree(cleanVisitor)

// Count files and directories with size calculation
var totalFiles = 0
var totalDirs = 0
var totalSize = 0L

projectDir.visitFileTree {
    onPreVisitDirectory { directory, _ ->
        totalDirs++
        FileVisitResult.CONTINUE
    }
    
    onVisitFile { file, attributes ->
        totalFiles++
        totalSize += attributes.size()
        FileVisitResult.CONTINUE
    }
}

println("Project statistics:")
println("- Directories: $totalDirs")
println("- Files: $totalFiles")
println("- Total size: ${totalSize / 1024 / 1024} MB")

// Find large files with depth limit
val largeFiles = mutableListOf<Pair<Path, Long>>()

projectDir.visitFileTree(maxDepth = 3) {
    onVisitFile { file, attributes ->
        val size = attributes.size()
        if (size > 10_000_000) { // Files larger than 10MB
            largeFiles.add(file to size)
        }
        FileVisitResult.CONTINUE
    }
}

println("Large files (>10MB):")
largeFiles.sortedByDescending { it.second }.forEach { (file, size) ->
    println("${size / 1024 / 1024} MB: ${file.relativeTo(projectDir)}")
}

File Visitor Builder Interface

Comprehensive interface for building custom file visitors with event handlers.

/**
 * The builder to provide implementation of the FileVisitor that fileVisitor function builds.
 */
@SinceKotlin("2.1")
interface FileVisitorBuilder {
    /**
     * Overrides the corresponding function of the built FileVisitor with the provided function.
     * The provided callback is invoked for a directory before its contents are visited.
     */
    fun onPreVisitDirectory(function: (directory: Path, attributes: BasicFileAttributes) -> FileVisitResult)
    
    /**
     * Overrides the corresponding function of the built FileVisitor with the provided function.
     * The provided callback is invoked when a file is visited.
     */
    fun onVisitFile(function: (file: Path, attributes: BasicFileAttributes) -> FileVisitResult)
    
    /**
     * Overrides the corresponding function of the built FileVisitor with the provided function.
     * The provided callback is invoked for an entry that could not be visited for some reason.
     */
    fun onVisitFileFailed(function: (file: Path, exception: IOException) -> FileVisitResult)
    
    /**
     * Overrides the corresponding function of the built FileVisitor with the provided function.
     * The provided callback is invoked for a directory after its contents have been visited.
     */
    fun onPostVisitDirectory(function: (directory: Path, exception: IOException?) -> FileVisitResult)
}

Usage Examples:

import kotlin.io.path.*
import java.nio.file.*
import java.nio.file.attribute.BasicFileAttributes
import java.io.IOException

val sourceDir = Paths.get("/home/user/source")
val reportFile = Paths.get("/home/user/analysis-report.txt")

// Comprehensive file analysis visitor
val analysisReport = mutableListOf<String>()

val analysisVisitor = fileVisitor {
    onPreVisitDirectory { directory, attributes ->
        analysisReport.add("ENTER DIR: ${directory.name} (created: ${attributes.creationTime()})")
        FileVisitResult.CONTINUE
    }
    
    onVisitFile { file, attributes ->
        val size = attributes.size()
        val modified = attributes.lastModifiedTime()
        val type = when (file.extension.lowercase()) {
            "kt", "java", "scala" -> "Source Code"
            "xml", "json", "yaml", "yml" -> "Configuration"  
            "md", "txt", "rst" -> "Documentation"
            "jpg", "png", "gif", "svg" -> "Image"
            else -> "Other"
        }
        
        analysisReport.add("FILE: ${file.name} | Type: $type | Size: $size bytes | Modified: $modified")
        FileVisitResult.CONTINUE
    }
    
    onVisitFileFailed { file, exception ->
        analysisReport.add("FAILED: ${file.name} | Error: ${exception.message}")
        FileVisitResult.CONTINUE // Continue despite errors
    }
    
    onPostVisitDirectory { directory, exception ->
        if (exception != null) {
            analysisReport.add("DIR ERROR: ${directory.name} | ${exception.message}")
        } else {
            analysisReport.add("EXIT DIR: ${directory.name}")
        }
        FileVisitResult.CONTINUE
    }
}

// Run analysis
sourceDir.visitFileTree(analysisVisitor)

// Write report
reportFile.writeLines(analysisReport)
println("Analysis complete. Report written to: $reportFile")

// Search visitor with early termination
var targetFound = false
val searchTerm = "important-file.txt"

val searchVisitor = fileVisitor {
    onVisitFile { file, _ ->
        if (file.name == searchTerm) {
            println("Found target file: $file")
            targetFound = true
            FileVisitResult.TERMINATE // Stop the entire traversal
        } else {
            FileVisitResult.CONTINUE
        }
    }
    
    onPreVisitDirectory { directory, _ ->
        // Skip hidden directories
        if (directory.name.startsWith(".")) {
            FileVisitResult.SKIP_SUBTREE
        } else {
            FileVisitResult.CONTINUE
        }
    }
}

sourceDir.visitFileTree(searchVisitor)

if (targetFound) {
    println("Search completed - target found!")
} else {
    println("Search completed - target not found.")
}

Advanced Tree Traversal Patterns

Complex patterns combining walking and visitor approaches for sophisticated file operations.

Usage Examples:

import kotlin.io.path.*
import java.nio.file.*
import java.time.Instant
import java.time.temporal.ChronoUnit

val projectRoot = Paths.get("/home/user/projects")
val backupDir = Paths.get("/backup/projects")
val archiveDir = Paths.get("/archive")

// Multi-pass processing: analyze then act
// Pass 1: Collect statistics
data class DirectoryStats(var fileCount: Int = 0, var totalSize: Long = 0, var lastModified: Instant = Instant.MIN)

val dirStats = mutableMapOf<Path, DirectoryStats>()

projectRoot.walk(PathWalkOption.INCLUDE_DIRECTORIES).forEach { path ->
    if (path.isDirectory()) {
        dirStats[path] = DirectoryStats()
    }
}

projectRoot.walk().forEach { file ->
    val parent = file.parent
    if (parent != null && parent in dirStats) {
        val stats = dirStats[parent]!!
        stats.fileCount++
        stats.totalSize += file.fileSize()
        val fileModified = file.getLastModifiedTime().toInstant()
        if (fileModified.isAfter(stats.lastModified)) {
            stats.lastModified = fileModified
        }
    }
}

// Pass 2: Archive old directories
val oneYearAgo = Instant.now().minus(365, ChronoUnit.DAYS)

dirStats.filter { (_, stats) -> 
    stats.lastModified.isBefore(oneYearAgo) && stats.fileCount > 0 
}.forEach { (dir, stats) ->
    println("Archiving old directory: $dir (${stats.fileCount} files, ${stats.totalSize / 1024 / 1024} MB)")
    
    val archivePath = archiveDir / dir.relativeTo(projectRoot)
    archivePath.createParentDirectories()
    dir.copyToRecursively(archivePath, followLinks = false, overwrite = true)
    dir.deleteRecursively()
}

// Selective backup with filtering
val importantExtensions = setOf("kt", "java", "xml", "md", "gradle")
val lastBackup = Instant.now().minus(7, ChronoUnit.DAYS)

projectRoot.walk()
    .filter { file ->
        file.extension in importantExtensions &&
        file.getLastModifiedTime().toInstant().isAfter(lastBackup)
    }
    .forEach { file ->
        val backupPath = backupDir / file.relativeTo(projectRoot)
        backupPath.createParentDirectories()
        file.copyTo(backupPath, overwrite = true)
        println("Backed up: ${file.relativeTo(projectRoot)}")
    }

// Complex filtering with visitor pattern
val duplicateFiles = mutableMapOf<Long, MutableList<Path>>()

projectRoot.visitFileTree {
    onVisitFile { file, attributes ->
        val size = attributes.size()
        duplicateFiles.computeIfAbsent(size) { mutableListOf() }.add(file)
        FileVisitResult.CONTINUE
    }
}

// Find potential duplicates (same size)
val potentialDuplicates = duplicateFiles.filter { (_, files) -> files.size > 1 }

println("Potential duplicate files (same size):")
potentialDuplicates.forEach { (size, files) ->
    println("Size: $size bytes")
    files.forEach { file ->
        println("  - ${file.relativeTo(projectRoot)}")
    }
    println()
}

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-kotlin--kotlin-stdlib-jdk7

docs

file-io.md

file-system.md

index.md

path-operations.md

recursive-operations.md

tree-traversal.md

tile.json