(原创)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:遍历过程中可能遇到权限问题、文件不存在等异常,需要处理

相关推荐
Yang-Never2 小时前
Android 内存泄漏 -> LiveData如何解决ViewMode和Activity/Fragment之间的内存泄漏
android·java·开发语言·kotlin·android studio
HeDongDong-2 小时前
Kotlin 协程(Coroutines)详解
android·开发语言·kotlin
allk553 小时前
Android APK 极限瘦身:从构建链优化到架构演进
android·架构
啊西:3 小时前
SuperMap iMobile for Android中模型按照指定路径运动
android
码农101号3 小时前
Ansible - Role介绍 和 使用playbook部署wordPress
android·ansible
a_eastern3 小时前
linux electron-forge离线打包关键配置
android·linux·electron
城东米粉儿3 小时前
Dynamic Feature Modules 笔记
android
无言Echo3 小时前
Android 高斯模糊(1) 窗口模糊及java侧基本流程简述
android
无言Echo3 小时前
Android 高斯模糊(2)BackgroundBlurDrawable使用及相关Bug
android