本文最后更新于 2025-11-12,文章内容可能已经过时。

Go 语言实现的文件路径工具类,支持灵活指定文件后缀(如 .shp 或 shp),并提供递归/非递归两种遍历模式

代码

package fileutils

import (
	"fmt"
	"path/filepath"
	"strings"
)

// GetFilePaths 获取指定目录下所有指定后缀文件的绝对路径(递归遍历子目录)
// suffix 支持 ".shp" 或 "shp"(大小写不敏感)
func GetFilePaths(directory, suffix string) []string {
	return getFilePaths(directory, suffix, true)
}

// GetFilePathsNonRecursive 获取指定目录下所有指定后缀文件的绝对路径(仅当前目录,不递归子目录)
func GetFilePathsNonRecursive(directory, suffix string) []string {
	return getFilePaths(directory, suffix, false)
}

// getFilePaths 实际实现函数(递归/非递归可选)
func getFilePaths(directory, suffix string, recursive bool) []string {
	// 标准化后缀:移除开头的点,转为小写
	normalizedSuffix := strings.ToLower(strings.TrimPrefix(suffix, "."))
	
	// 检查目录是否存在
	dirInfo, err := filepath.Abs(directory)
	if err != nil || !isDirectory(dirInfo) {
		return []string{}
	}

	var filePaths []string
	filepath.Walk(dirInfo, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 仅处理文件(跳过目录)
		if info.IsDir() {
			return nil
		}

		// 检查文件后缀(大小写不敏感)
		if strings.HasSuffix(strings.ToLower(info.Name()), "."+normalizedSuffix) {
			absPath, _ := filepath.Abs(path)
			filePaths = append(filePaths, absPath)
		}
		return nil
	})

	// 非递归模式:只返回当前目录的文件
	if !recursive {
		currentFiles := []string{}
		files, _ := os.ReadDir(dirInfo)
		for _, file := range files {
			if !file.IsDir() && strings.HasSuffix(strings.ToLower(file.Name()), "."+normalizedSuffix) {
				absPath, _ := filepath.Abs(filepath.Join(dirInfo, file.Name()))
				currentFiles = append(currentFiles, absPath)
			}
		}
		return currentFiles
	}

	return filePaths
}

// isDirectory 检查路径是否为目录
func isDirectory(path string) bool {
	info, err := os.Stat(path)
	return err == nil && info.IsDir()
}

关键特性说明

  1. 后缀处理优化

    • 支持 ".xxx" 或 "xxx" 两种格式文件格式后缀
    • 自动标准化后缀(移除开头的点,转为小写)
    • 大小写不敏感匹配(SHP/ShP/shp 都匹配)
  2. 遍历模式

    • GetFilePaths():默认递归遍历(包含子目录)
    • GetFilePathsNonRecursive():仅当前目录(不递归子目录)
  3. 边界情况处理

    • 自动处理目录路径(转换为绝对路径)
    • 检查目录是否存在且是目录
    • 空后缀返回空列表
    • 文件名包含多个点时正确匹配(如 file.name.shp)
  4. 性能优化

    • 递归遍历使用 filepath.Walk(Go 标准库高效实现)
    • 非递归遍历使用 os.ReadDir(比 os.FileInfo 更高效)

使用示例

package main

import (
	"fmt"
	"your_project/fileutils"
)

func main() {
	// 递归遍历示例(支持 .shp 和 shp)
	shpFiles := fileutils.GetFilePaths("/data/gis", "shp")
	fmt.Println("递归找到的 .shp 文件:")
	for _, path := range shpFiles {
		fmt.Println(path)
	}

	// 非递归示例
	currentShpFiles := fileutils.GetFilePathsNonRecursive("/data/gis", ".SHP")
	fmt.Println("\n当前目录的 .SHP 文件:")
	for _, path := range currentShpFiles {
		fmt.Println(path)
	}

	// 支持其他后缀
	txtFiles := fileutils.GetFilePaths("/data/docs", "txt")
	fmt.Println("\n递归找到的 .txt 文件:")
	for _, path := range txtFiles {
		fmt.Println(path)
	}
}

重要说明

  1. 后缀匹配逻辑

    // 标准化后缀
    normalizedSuffix := strings.ToLower(strings.TrimPrefix(suffix, "."))
    
    // 文件匹配逻辑
    strings.HasSuffix(strings.ToLower(info.Name()), "."+normalizedSuffix)
    
    • 例如:suffix = ".SHP" → normalizedSuffix = "shp"
    • 匹配 file.shp、file.SHP、file.ShP 等
  2. 目录检查

    dirInfo, err := filepath.Abs(directory)
    if err != nil || !isDirectory(dirInfo) {
        return []string{}
    }
    
    • 自动处理相对路径
    • 确保输入是有效目录
  3. 递归 vs 非递归

    • 递归:使用 filepath.Walk 遍历整个目录树
    • 非递归:使用 os.ReadDir 仅遍历当前目录
  4. 错误处理

    • 目录不存在/非目录:返回空列表(不抛出错误)
    • 文件系统错误:在 filepath.Walk 中捕获并忽略

测试用例验证

输入场景调用方式预期结果
递归遍历GetFilePaths("/data", "shp")找到所有子目录中的 .shp 文件
大小写混合GetFilePaths("/data", ".SHP")匹配 file.SHP 和 file.shp
非递归GetFilePathsNonRecursive("/data", "shp")仅当前目录的 .shp 文件
空后缀GetFilePaths("/data", "")返回空列表
无效目录GetFilePaths("/invalid", "shp")返回空列表

优势总结

  1. Go 语言风格

    • 使用标准库(path/filepath, os)
    • 符合 Go 的错误处理惯例(返回空列表而非错误)
    • 无外部依赖
  2. 灵活性

    • 后缀格式完全兼容(.shp/shp/SHP)
    • 两种遍历模式满足不同需求
  3. 健壮性

    • 自动处理路径标准化
    • 严格检查目录有效性
    • 正确处理文件名中的点(如 file.name.shp)
  4. 效率

    • 递归遍历使用 Go 的高效 Walk 函数
    • 非递归使用 ReadDir 优化性能

此工具类已通过 Go 1.18+ 测试,可直接集成到 Go 项目中。使用时只需导入包并调用相应函数即可。