如何检查路径上的目录是否为空?

21

如何在Go中检查文件夹是否为空?我可以这样检查:

files, err := ioutil.ReadDir(*folderName)
if err != nil {
    return nil, err
}

// here check len of files 

但在我看来,似乎应该有更加优雅的解决方案。


1
你可以使用 f.Readdir(1) 只查看第一个目录条目(如果需要跳过“.”和“..”,则为3)(如果可能有许多目录条目,则很有帮助)。但要注意,你只能知道“目录曾经为空”,在你检查时它可能已经有新文件了。这可能是没有“简单”检查存在的原因之一;因为它相当无用。[例如,这就是为什么像 rmdir 这样的东西不会检查,它们只是尝试删除目录并处理/报告 ENOTEMPTY,因为那是原子操作。] - Dave C
1
实际上,f.Readdirnames(1)(或3)会更好一些。 - Dave C
1个回答

45

无论一个目录是否为空,都不会像名字、创建时间或大小(针对文件)这样作为文件系统级别的属性来存储。

话虽如此,你不能仅通过查询 os.FileInfo 来获取这些信息。最简单的方式是查询目录的子项(内容)。

ioutil.ReadDir() 是相当糟糕的选择,因为它首先读取指定目录所有内容,然后按名称排序,并返回切片。最快的方法是像 Dave C 提到的那样:使用 File.Readdir() 或者(更好地),File.Readdirnames() 查询目录的子项。

File.Readdir()File.Readdirnames() 都需要一个参数,用于限制返回的值数。只查询一个子项就足够了。因为 Readdirnames() 只返回名称,所以它更快,因为不需要进一步调用获取(和构造)FileInfo 结构。

请注意,如果目录为空,则会返回 io.EOF 作为错误(而不是空或 nil 切片),因此我们甚至不需要返回的名称切片。

最终代码可能如下所示:

func IsEmpty(name string) (bool, error) {
    f, err := os.Open(name)
    if err != nil {
        return false, err
    }
    defer f.Close()

    _, err = f.Readdirnames(1) // Or f.Readdir(1)
    if err == io.EOF {
        return true, nil
    }
    return false, err // Either not empty or error, suits both cases
}

File.Readdirnames() 的实现似乎基于 File.Readdir() - mat007
现在最好使用 File.ReadDir() 吗? - silencej
关于golang:1.19,最好使用File.Readdirnames(),因为它的实现只读取名称,而File.Readdir还会读取每个找到的文件的统计信息。请参见https://go.dev/src/os/dir_windows.go第40行。 - Mikhail Kopylov
@MikhailKopylov 这正是答案所建议的。 - icza
没错。刚刚添加了一个链接,解释了为什么。 - Mikhail Kopylov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接