英文:
List directory in Go
问题
我一直在尝试找出如何在Go中简单地列出单个目录中的文件和文件夹。
我找到了filepath.Walk
,但它会自动进入子目录,这不是我想要的。我所有的其他搜索都没有找到更好的解决方案。
我确定这个功能是存在的,但是很难找到。如果有人知道我应该去哪里找,请告诉我。谢谢。
英文:
I've been trying to figure out how to simply list the files and folders in a single directory in Go.
I've found filepath.Walk
, but it goes into sub-directories automatically, which I don't want. All of my other searches haven't turned anything better up.
I'm sure that this functionality exists, but it's been really hard to find. Let me know if anyone knows where I should look. Thanks.
答案1
得分: 471
你可以尝试使用os
包中的ReadDir函数。根据文档:
> ReadDir读取指定的目录,并按文件名对其所有目录条目进行排序。
返回的切片包含os.DirEntry
类型,该类型提供了这里列出的方法。以下是一个基本示例,列出当前目录中所有内容的名称(包括文件夹,但没有特殊标记 - 你可以使用IsDir()
方法来检查一个项目是否是文件夹):
package main
import (
"fmt"
"os"
"log"
)
func main() {
entries, err := os.ReadDir("./")
if err != nil {
log.Fatal(err)
}
for _, e := range entries {
fmt.Println(e.Name())
}
}
英文:
You can try using the ReadDir function in the os
package. Per the docs:
> ReadDir reads the named directory, returning all its directory entries sorted by filename.
The resulting slice contains os.DirEntry
types, which provide the methods listed here. Here is a basic example that lists the name of everything in the current directory (folders are included but not specially marked - you can check if an item is a folder by using the IsDir()
method):
package main
import (
"fmt"
"os"
"log"
)
func main() {
entries, err := os.ReadDir("./")
if err != nil {
log.Fatal(err)
}
for _, e := range entries {
fmt.Println(e.Name())
}
}
答案2
得分: 112
我们可以使用各种golang标准库函数来获取文件系统中文件夹内的文件列表。
- filepath.Walk
- ioutil.ReadDir
- os.File.Readdir
<pre><code>
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
)
func main() {
var (
root string
files []string
err error
)
root := "/home/manigandan/golang/samples"
// filepath.Walk
files, err = FilePathWalkDir(root)
if err != nil {
panic(err)
}
// ioutil.ReadDir
files, err = IOReadDir(root)
if err != nil {
panic(err)
}
//os.File.Readdir
files, err = OSReadDir(root)
if err != nil {
panic(err)
}
for _, file := range files {
fmt.Println(file)
}
}
</code></pre>
- 使用filepath.Walk
> path/filepath
包提供了一种方便的方式来扫描目录中的所有文件,它会自动扫描目录中的每个子目录。
func FilePathWalkDir(root string) ([]string, error) {
var files []string
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
files = append(files, path)
}
return nil
})
return files, err
}
- 使用ioutil.ReadDir
> ioutil.ReadDir
读取由dirname指定的目录,并按文件名排序返回一个目录条目列表。
func IOReadDir(root string) ([]string, error) {
var files []string
fileInfo, err := ioutil.ReadDir(root)
if err != nil {
return files, err
}
for _, file := range fileInfo {
files = append(files, file.Name())
}
return files, nil
}
- 使用os.File.Readdir
> Readdir读取与文件关联的目录的内容,并按目录顺序返回最多n个FileInfo值的切片,就像Lstat返回的那样。对同一个文件的后续调用将产生更多的FileInfos。
func OSReadDir(root string) ([]string, error) {
var files []string
f, err := os.Open(root)
if err != nil {
return files, err
}
fileInfo, err := f.Readdir(-1)
f.Close()
if err != nil {
return files, err
}
for _, file := range fileInfo {
files = append(files, file.Name())
}
return files, nil
}
基准测试结果。
获取更多详细信息,请参阅博客文章
英文:
We can get a list of files inside a folder on the file system using various golang standard library functions.
- filepath.Walk
- ioutil.ReadDir
- os.File.Readdir
<pre><code>
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
)
func main() {
var (
root string
files []string
err error
)
root := "/home/manigandan/golang/samples"
// filepath.Walk
files, err = FilePathWalkDir(root)
if err != nil {
panic(err)
}
// ioutil.ReadDir
files, err = IOReadDir(root)
if err != nil {
panic(err)
}
//os.File.Readdir
files, err = OSReadDir(root)
if err != nil {
panic(err)
}
for _, file := range files {
fmt.Println(file)
}
}
</code></pre>
- Using filepath.Walk
> The path/filepath
package provides a handy way to scan all the files
> in a directory, it will automatically scan each sub-directories in the
> directory.
func FilePathWalkDir(root string) ([]string, error) {
var files []string
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
files = append(files, path)
}
return nil
})
return files, err
}
- Using ioutil.ReadDir
> ioutil.ReadDir
reads the directory named by dirname and returns a
> list of directory entries sorted by filename.
func IOReadDir(root string) ([]string, error) {
var files []string
fileInfo, err := ioutil.ReadDir(root)
if err != nil {
return files, err
}
for _, file := range fileInfo {
files = append(files, file.Name())
}
return files, nil
}
- Using os.File.Readdir
> Readdir reads the contents of the directory associated with file and
> returns a slice of up to n FileInfo values, as would be returned by
> Lstat, in directory order. Subsequent calls on the same file will
> yield further FileInfos.
func OSReadDir(root string) ([]string, error) {
var files []string
f, err := os.Open(root)
if err != nil {
return files, err
}
fileInfo, err := f.Readdir(-1)
f.Close()
if err != nil {
return files, err
}
for _, file := range fileInfo {
files = append(files, file.Name())
}
return files, nil
}
Benchmark results.
Get more details on this Blog Post
答案3
得分: 81
更简单的方法是使用path/filepath
:
package main
import (
"fmt"
"log"
"path/filepath"
)
func main() {
files, err := filepath.Glob("*")
if err != nil {
log.Fatal(err)
}
fmt.Println(files) // 包含当前目录中所有文件的列表
}
英文:
Even simpler, use path/filepath
:
package main
import (
"fmt"
"log"
"path/filepath"
)
func main() {
files, err := filepath.Glob("*")
if err != nil {
log.Fatal(err)
}
fmt.Println(files) // contains a list of all files in the current directory
}
答案4
得分: 28
从Go 1.16开始,您可以使用os.ReadDir函数。
> func ReadDir(name string) ([]DirEntry, error)
它读取给定的目录并返回一个包含按文件名排序的目录条目的DirEntry
切片。
这是一个乐观的函数,所以当在读取目录条目时发生错误时,它会尝试返回一个在错误之前的点之前的文件名切片。
package main
import (
"fmt"
"log"
"os"
)
func main() {
files, err := os.ReadDir(".")
if err != nil {
log.Fatal(err)
}
for _, file := range files {
fmt.Println(file.Name())
}
}
有趣的是:Go 1.17(2021年第三季度)包括fs.FileInfoToDirEntry()
:
>go >func FileInfoToDirEntry(info FileInfo) DirEntry >
>
> FileInfoToDirEntry
返回一个返回来自info
的信息的DirEntry
。
如果info
为nil,则FileInfoToDirEntry
返回nil。
英文:
Starting with Go 1.16, you can use the os.ReadDir function.
> func ReadDir(name string) ([]DirEntry, error)
It reads a given directory and returns a DirEntry
slice that contains the directory entries sorted by filename.
It's an optimistic function, so that, when an error occurs while reading the directory entries, it tries to return you a slice with the filenames up to the point before the error.
package main
import (
"fmt"
"log"
"os"
)
func main() {
files, err := os.ReadDir(".")
if err != nil {
log.Fatal(err)
}
for _, file := range files {
fmt.Println(file.Name())
}
}
Of interest: Go 1.17 (Q3 2021) includes fs.FileInfoToDirEntry()
:
>go
>func FileInfoToDirEntry(info FileInfo) DirEntry
>
>
> FileInfoToDirEntry
returns a DirEntry
that returns information from info
.
If info
is nil, FileInfoToDirEntry
returns nil.
Background
Go 1.16 (Q1 2021) will propose, with CL 243908 and CL 243914 , the ReadDir
function, based on the FS
interface:
// An FS provides access to a hierarchical file system.
//
// The FS interface is the minimum implementation required of the file system.
// A file system may implement additional interfaces,
// such as fsutil.ReadFileFS, to provide additional or optimized functionality.
// See io/fsutil for details.
type FS interface {
// Open opens the named file.
//
// When Open returns an error, it should be of type *PathError
// with the Op field set to "open", the Path field set to name,
// and the Err field describing the problem.
//
// Open should reject attempts to open names that do not satisfy
// ValidPath(name), returning a *PathError with Err set to
// ErrInvalid or ErrNotExist.
Open(name string) (File, error)
}
That allows for "os: add ReadDir
method for lightweight directory reading":
See commit a4ede9f:
// ReadDir reads the contents of the directory associated with the file f
// and returns a slice of DirEntry values in directory order.
// Subsequent calls on the same file will yield later DirEntry records in the directory.
//
// If n > 0, ReadDir returns at most n DirEntry records.
// In this case, if ReadDir returns an empty slice, it will return an error explaining why.
// At the end of a directory, the error is io.EOF.
//
// If n <= 0, ReadDir returns all the DirEntry records remaining in the directory.
// When it succeeds, it returns a nil error (not io.EOF).
func (f *File) ReadDir(n int) ([]DirEntry, error)
// A DirEntry is an entry read from a directory (using the ReadDir method).
type DirEntry interface {
// Name returns the name of the file (or subdirectory) described by the entry.
// This name is only the final element of the path, not the entire path.
// For example, Name would return "hello.go" not "/home/gopher/hello.go".
Name() string
// IsDir reports whether the entry describes a subdirectory.
IsDir() bool
// Type returns the type bits for the entry.
// The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method.
Type() os.FileMode
// Info returns the FileInfo for the file or subdirectory described by the entry.
// The returned FileInfo may be from the time of the original directory read
// or from the time of the call to Info. If the file has been removed or renamed
// since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist).
// If the entry denotes a symbolic link, Info reports the information about the link itself,
// not the link's target.
Info() (FileInfo, error)
}
src/os/os_test.go#testReadDir()
illustrates its usage:
file, err := Open(dir)
if err != nil {
t.Fatalf("open %q failed: %v", dir, err)
}
defer file.Close()
s, err2 := file.ReadDir(-1)
if err2 != nil {
t.Fatalf("ReadDir %q failed: %v", dir, err2)
}
Ben Hoyt points out in the comments to Go 1.16 os.ReadDir
:
> os.ReadDir(path string) ([]os.DirEntry, error)
, which you'll be able to call directly without the Open
dance.
So you can probably shorten this to just os.ReadDir
, as that's the concrete function most people will call.
See commit 3d913a9 (Dec. 2020):
> ## os
: add ReadFile
, WriteFile
, CreateTemp
(was TempFile
), MkdirTemp
(was TempDir
) from io/ioutil
>
> io/ioutil
was a poorly defined collection of helpers.
>
> Proposal #40025 moved out the generic I/O helpers to io.
This CL for proposal #42026 moves the OS-specific helpers to os
,
making the entire io/ioutil
package deprecated.
> os.ReadDir
returns []DirEntry
, in contrast to ioutil.ReadDir
's []FileInfo
.
(Providing a helper that returns []DirEntry
is one of the primary motivations for this change.)
答案5
得分: 23
ioutil.ReadDir
是一个很好的发现,但是如果你点击并查看源代码,你会发现它调用了os.File的Readdir方法。如果你对目录的顺序没有要求,也不需要对列表进行排序,那么这个Readdir方法就足够了。
英文:
ioutil.ReadDir
is a good find, but if you click and look at the source you see that it calls the method Readdir of os.File. If you are okay with the directory order and don't need the list sorted, then this Readdir method is all you need.
答案6
得分: 18
根据您的描述,您可能想要使用os.Readdirnames。
> func (f *File) Readdirnames(n int) (names []string, err error)
>
> Readdirnames函数读取与文件关联的目录的内容,并以目录顺序返回最多n个文件名的切片。对同一文件的后续调用将返回更多的文件名。
>
> ...
>
> 如果n <= 0,则Readdirnames函数将在一个切片中返回目录中的所有文件名。
代码片段:
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
names, err := file.Readdirnames(0)
if err != nil {
return err
}
fmt.Println(names)
感谢SquattingSlavInTracksuit的评论;如果可以的话,我会建议将他们的评论提升为答案。
英文:
From your description, what you probably want is os.Readdirnames.
> func (f *File) Readdirnames(n int) (names []string, err error)
>
> Readdirnames reads the contents of the directory associated with file and returns a slice of up to n names of files in the directory, in directory order. Subsequent calls on the same file will yield further names.
>
> ...
>
> If n <= 0, Readdirnames returns all the names from the directory in a single slice.
Snippet:
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
names, err := file.Readdirnames(0)
if err != nil {
return err
}
fmt.Println(names)
Credit to SquattingSlavInTracksuit's comment; I'd have suggested promoting their comment to an answer if I could.
答案7
得分: 5
使用Readdirnames
递归打印目录中的所有文件的完整示例
package main
import (
"fmt"
"os"
)
func main() {
path := "/path/to/your/directory"
err := readDir(path)
if err != nil {
panic(err)
}
}
func readDir(path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
names, _ := file.Readdirnames(0)
for _, name := range names {
filePath := fmt.Sprintf("%v/%v", path, name)
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
fileInfo, err := file.Stat()
if err != nil {
return err
}
fmt.Println(filePath)
if fileInfo.IsDir() {
readDir(filePath)
}
}
return nil
}
英文:
A complete example of printing all the files in a directory recursively using Readdirnames
package main
import (
"fmt"
"os"
)
func main() {
path := "/path/to/your/directory"
err := readDir(path)
if err != nil {
panic(err)
}
}
func readDir(path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
names, _ := file.Readdirnames(0)
for _, name := range names {
filePath := fmt.Sprintf("%v/%v", path, name)
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
fileInfo, err := file.Stat()
if err != nil {
return err
}
fmt.Println(filePath)
if fileInfo.IsDir() {
readDir(filePath)
}
}
return nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论