(原创)Android遍历文件方法walk函数介绍

前言

最近搞了一个文件遍历功能,发现kotlin语言提供了新的函数Walk()

walk() 是 Kotlin 标准库中为 File 类提供的扩展函数,用于遍历文件系统的树形结构。

发现这个函数还是蛮强大的,于是做了个整理

下面介绍它的基本功能和一些使用注意

遍历文件

最基本的遍历文件操作使用很简单,代码如下:

kotlin 复制代码
File("/path/directory").walk().forEach { file ->
    println("${if (file.isDirectory) "目录" else "文件"}: ${file.absolutePath}")
}

这里就可以对整个文件夹的文件做一个遍历,打印出是目录还是文件

遍历方向

walk()函数可以控制遍历方向,从上到下还是从下到上

它传入一个FileWalkDirection枚举类,如下:

kotlin 复制代码
File(".").walk(FileWalkDirection.TOP_DOWN).forEach { println(it.path) }

这个FileWalkDirection有两个选项:

TOP_DOWN和BOTTOM_UP

其中TOP_DOWN是默认的

过滤文件

有时候我们不需要遍历文件夹下所有文件,而是有一些规则

可以使用filter,如下:

kotlin 复制代码
// 只获取文件(排除目录)
val filesOnly = File(".").walk()
    .filter { it.isFile }
    .toList()

限制遍历深度

这里也是一个过滤方式,比如只需要第一层文件,就这样写:

kotlin 复制代码
// 只遍历当前目录(深度0)
File(".").walk().maxDepth(0).forEach { }

maxDepth可以传入具体的层级:

kotlin 复制代码
// 遍历当前目录和一级子目录
File(".").walk().maxDepth(1).forEach { }

// 遍历当前目录到三级子目录
File(".").walk().maxDepth(3).forEach { }

当然还可以从第一级子目录开始(跳过当前目录)

kotlin 复制代码
// 从第一级子目录开始(跳过当前目录)
File(".").walk().minDepth(1).forEach { }

文件查找

查找指定的文件可以这样做:

kotlin 复制代码
// 查找名为 config.json 的文件
val configFile = File(".").walk()
    .firstOrNull { it.name == "config.json" }

// 查找所有 .txt 文件
val textFiles = File(".").walk()
    .filter { it.extension == "txt" }
    .toList()

或者查找包含特定内容的文件

kotlin 复制代码
val kotlinFiles = File(".").walk()
    .filter { it.isFile }
    .filter { file ->
        file.readText().contains("fun main()")
    }
    .toList()

排序和限制

还有一些更灵活的操作:

kotlin 复制代码
// 按文件大小排序
val sortedBySize = File(".").walk()
    .filter { it.isFile }
    .sortedBy { it.length() }
    .toList()

// 按修改时间排序
val sortedByDate = File(".").walk()
    .filter { it.isFile }
    .sortedBy { it.lastModified() }
    .toList()

// 获取前10个文件
val firstTen = File(".").walk()
    .filter { it.isFile }
    .take(10)
    .toList()

// 跳过前5个文件
val afterFirstFive = File(".").walk()
    .filter { it.isFile }
    .drop(5)
    .toList()

#文件统计

当我们只需要文件数量,或者一些其他的数据,可以这样:

kotlin 复制代码
// 统计文件数量
val fileCount = File(".").walk()
    .count { it.isFile }

// 统计目录数量
val dirCount = File(".").walk()
    .count { it.isDirectory }

// 计算总大小
val totalSize = File(".").walk()
    .filter { it.isFile }
    .sumOf { it.length() }

// 按扩展名分组
val filesByExtension = File(".").walk()
    .filter { it.isFile }
    .groupBy { it.extension }

// 获取最大的文件
val largestFile = File(".").walk()
    .filter { it.isFile }
    .maxByOrNull { it.length() }

这里groupBy会返回一个map集合:

Map<K, List>

key是groupBy返回的值,value就是每个组的集合了

访问权限处理

有的文件夹下的文件无法访问,也就是没有权限,这时候可以这样处理:

kotlin 复制代码
fun safeWalk(directory: File): Sequence<File> {
    return try {
        directory.walk().onEach { 
            if (!it.canRead()) {
                println("无法访问: ${it.absolutePath}")
            }
        }
    } catch (e: SecurityException) {
        println("没有访问权限: ${directory.absolutePath}")
        emptySequence()
    }
}

使用协程处理大目录

当文件特别多的时候,要考虑性能问题,可以分批次处理:

kotlin 复制代码
suspend fun processLargeDirectory(directory: File) = withContext(Dispatchers.IO) {
    directory.walk()
        .chunked(100)  // 分批处理,每批100个文件
        .forEach { batch ->
            // 处理一批文件
            batch.forEach { file ->
                // 处理每个文件
            }
            // 可以在这里 yield 一下,避免阻塞
            yield()
        }
}

注意事项

1:使用 toList() 等终端操作会将所有结果加载到内存,大目录慎用,我们可以用forEach逐个处理文件,不一次性加载到内存

2:walk() 创建的是序列(Sequence),是惰性求值的,适合处理大量文件

3:注意设置合理的 maxDepth,避免栈溢出

4:遍历过程中可能遇到权限问题、文件不存在等异常,需要处理

相关推荐
胖虎19 分钟前
从一个自定义的下载Dialog,说清 Android 自定义弹窗的关键点。
android·dialog·gitee·自定义弹窗
UrSpecial12 分钟前
IM项目——用户管理子服务
android·adb
不会Android的潘潘38 分钟前
adb指令扩展方案
android·adb·aosp
2501_9151063240 分钟前
如何在 iOS 设备上理解和分析 CPU 使用率(windows环境)
android·ios·小程序·https·uni-app·iphone·webview
明飞19871 小时前
系统化掌握Android NDK开发 (JNI)
android
冬奇Lab1 小时前
【Kotlin系列09】委托机制与属性委托实战:组合优于继承的最佳实践
android·开发语言·kotlin
心前阳光1 小时前
Unity发布运行在PICO4的安卓程序
android·unity·游戏引擎
艾特 ljr0052 小时前
安卓报毒处理深度解析:权限使用频率与时机如何影响安全判定
android·android安全·安卓报毒处理·apk报毒·安卓安装提示风险
编程之路从0到12 小时前
React Native之Android端Fabric 架构源码分析
android·react native·源码分析·fabric