文件遍历

文件遍历这活儿,文件遍历说穿了就是文件遍历跟目录树死磕。你给程序一个根路径,文件遍历它就得像个不知疲倦的文件遍历邮差,挨家挨户敲开每个文件夹的文件遍历门,把里面的文件遍历文件清单全抄回来。这事儿听起来简单,文件遍历真做起来,文件遍历坑比想象中多。文件遍历

我去年接手过一个老项目,文件遍历里头有个功能要扫描服务器上几万个图片文件。文件遍历第一版代码写得挺天真,文件遍历递归嘛,文件遍历一层层往下钻,文件遍历遇到文件就记录路径。文件遍历本地测试没问题,一上生产环境就卡死,CPU飙到百分百,内存像漏了底的水桶。查了半天,发现是某个目录下套了符号链接,递归函数在那儿原地转圈,跟鬼打墙似的。后来加了visited集合,记录已经访问过的真实路径,才算把死循环给治了。

遍历策略也有讲究。深度优先和广度优先,看着差不多,实际用起来天差地别。深度优先省内存,适合目录层级深但每层文件少的场景,比如Java的maven仓库。广度优先则适合需要先看全局结构的场合,像文件管理器平铺展示所有子目录。我习惯用栈模拟递归,这样能手动控制遍历顺序,遇到权限不足的目录还能优雅地跳过,不至于整个程序崩掉。

真正让人头疼的是文件系统本身的怪脾气。Windows上路径分隔符是反斜杠,Linux是正斜杠,跨平台代码里要是写死了分隔符,准得闹笑话。还有文件名编码问题,中文、日文、韩文混在一起,一不小心就乱码。更别提那些带特殊字符的文件名——空格、括号、emoji,甚至换行符,都能让解析逻辑当场翻车。我见过最离谱的,是个文件名里藏着退格键的恶意文件,打印出来看着正常,实际上路径早就被篡改了。

性能优化这块儿,很多人一开始就走偏了。以为用多线程并行遍历能快几倍,结果磁盘I/O成了瓶颈,线程全在等硬盘响应,反而拖慢速度。我试过用异步非阻塞I/O,在SSD上确实有提升,但机械硬盘上效果不明显。最实用的技巧其实是减少系统调用次数——一次readdir拿完整个目录列表,别一个一个stat。批量操作比逐个请求快得多,这个道理跟去超市购物似的,一次性把清单上的东西全买了,比跑十趟便利店高效。

遍历完文件,接下来就是怎么处理这些结果。有人喜欢把路径全塞进内存里的列表,几万个文件还好说,到了几百万级别,内存就吃不消了。这时候得用迭代器模式,边遍历边处理,像流水线一样。我写过一个工具,每扫描到一个文件就立刻计算哈希值,同时把结果写入数据库,内存占用始终保持在几十兆以内。还有个细节容易忽略:文件可能在遍历过程中被删除或移动。你得做好心理准备,拿到的路径可能瞬间就失效了,处理异常时得留一手。

最后说点实在的。文件遍历看着是基础功能,但写得好不好,直接关系到整个应用的健壮性。别迷信现成的库函数,它们处理不了所有边界情况。自己动手写一遍,才能摸清文件系统的脾气。踩过那些坑之后,你会发现,遍历文件就像跟操作系统对话——你得顺着它的性子来,它才肯老老实实把家底都交给你。