filepath.walk 配合 strings.contains 可构建轻量文件内容搜索器,需先过滤非文本及过大文件,再对符合条件的文件逐行扫描匹配。

Go 的 filepath.Walk 配合 strings.Contains 就能快速实现一个轻量、无依赖的文件内容搜索器,不需要引入全文检索库。
用 filepath.Walk 递归遍历目录并过滤文件类型
直接硬扫整个磁盘效率低还容易 panic,得先筛掉非文本文件和过大文件。重点不是“走完所有路径”,而是“只处理可能匹配的文件”。
- 用
filepath.Walk遍历,但每个os.FileInfo都要检查:!info.IsDir()、info.Size() (限制 1MB 以内) - 扩展名白名单比黑名单更安全:只处理
.go、.txt、.md、.yml等可读文本后缀,跳过.png、.zip、.so - 注意:Windows 路径分隔符是
\,但filepath.Walk返回的路径在各平台都用/分隔,无需额外转义
逐行读取避免内存爆炸,用 bufio.Scanner 控制单行长度
大文件即使没超 1MB,也可能有超长单行(比如 minified JS),直接 io.ReadAll 容易 OOM。必须流式处理。
- 对每个候选文件,用
os.Open后传给bufio.NewScanner - 设置
scanner.Split(bufio.ScanLines)和scanner.Buffer(make([]byte, 4096), 1,防止超长行 panic - 每行用
strings.Contains(line, keyword)判断,匹配就输出fmt.Printf("%s:%d: %s\n", path, lineNum, line) - 别用
strings.Index或正则——简单子串搜索够用且快;真要正则再换regexp
支持命令行参数:路径、关键词、忽略大小写
用户不会改代码跑搜索,得靠 flag 解析参数。关键不是功能多,而是默认行为合理、报错明确。
- 必需参数:搜索路径(
-root)和关键词(-q),缺失就flag.Usage()+os.Exit(1) - 可选参数:
-i忽略大小写(内部转成小写比对),-ext自定义扩展名(如"-ext=.go,.rs") - 错误处理重点:如果
os.Stat(root)失败,直接打印fmt.Fprintf(os.Stderr, "invalid root: %v\n", err)并退出,不继续走Walk
为什么不用 grep -r?什么时候该换 bleve?
这个工具适合“临时查一下某个变量在哪被用到”,不是替代 ripgrep 或建索引服务。边界要清楚。
- 纯 Go 实现意味着跨平台二进制零依赖,编译完扔到服务器就能搜,但性能不如
rg(后者用 SIMD 和 mmap) - 如果需要模糊匹配、前缀搜索、高亮或百万级文件,立刻停手——
bleve或meilisearch是另一套工程,别往里塞正则和缓存逻辑 - 最容易被忽略的点:编码。Go 默认按 UTF-8 读,遇到 GBK 文件会乱码甚至
scanner.Err()报invalid UTF-8,此时应跳过而非 panic
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











