Go Fundamentals - Sample
Table of Contents
Chapter 14.1: Directory Entries and File Information
Before we can begin using files for our programs, we need to, first, understand the basics of how files work in Go.
Consider the following file tree. We will be using this file tree to aid in our understanding of files in Go. This tree contains .txt
files, as well as, special directories, testdata
, _ignore
, and .hidden
. We will cover the importance of these files, and directories, as we progress.
$ tree -a
.
├── .hidden
│ └── d.txt
├── a.txt
├── b.txt
├── e
│ ├── f
│ │ ├── _ignore
│ │ │ └── i.txt
│ │ ├── g.txt
│ │ └── h.txt
│ └── j.txt
└── testdata
└── c.txt
5 directories, 8 files
.hidden
, _ignore
, and testdata
.Reading a Directory
In order to know which files we can work with, we need to know which files are in a directory. To do this we can use the os.ReadDir
function, Listing 14.2.
$ go doc os.ReadDir
package os // import "os"
func ReadDir(name string) ([]DirEntry, error)
ReadDir reads the named directory, returning all its directory entries
sorted by filename. If an error occurs reading the directory, ReadDir
returns the entries it was able to read before the error, along with the
error.
--------------------------------------------------------------------------------
Go Version: go1.23.0
os.ReadDir
function.The os.ReadDir
function takes a path as a parameter, and returns a slice of os.DirEntry
values, Listing 14.3. Each os.DirEntry
value represents a file or directory in the directory, and contains information about the file or directory.
$ go doc os.DirEntry
package os // import "os"
type DirEntry = fs.DirEntry
A DirEntry is an entry read from a directory (using the ReadDir function or
a File.ReadDir method).
func ReadDir(name string) ([]DirEntry, error)
--------------------------------------------------------------------------------
Go Version: go1.23.0
os.DirEntry
type.In go1.16
the fs
package was added, which provides interface around the file system. The result of this was that many types were aliased to the fs
package. This means that you may need to hunt a little further to find the deeper documentation.
For example, os.DirEntry
was aliased to fs.DirEntry
in go1.16
, Listing 14.4.
$ go doc fs.DirEntry
package fs // import "io/fs"
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 (the base name), 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 directory.
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() 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)
}
A DirEntry is an entry read from a directory (using the ReadDir function or
a ReadDirFile's ReadDir method).
func FileInfoToDirEntry(info FileInfo) DirEntry
func ReadDir(fsys FS, name string) ([]DirEntry, error)
--------------------------------------------------------------------------------
Go Version: go1.23.0
fs.DirEntry
type.We can use the os.ReadDir
function to read the contents of the data
directory. We then print the names to the console. If the file is a directory, we prepend it with a ->
.
func main() {
files, err := os.ReadDir("data")
if err != nil {
log.Fatal(err)
}
for _, file := range files {
if file.IsDir() {
fmt.Println("->", file.Name())
continue
}
fmt.Println(file.Name())
}
}
os.ReadDir
to read the contents of a directory.As we can see from the output of the program, only the files in the data
directory are listed. The os.ReadDir
function will only read the contents of the directory, and not the contents of any subdirectories. To get a full list of files, including the contents of subdirectories, we will need to walk the directories ourselves. We will discuss this more later.
$ go run .
-> .hidden
a.txt
b.txt
-> e
-> testdata
--------------------------------------------------------------------------------
Go Version: go1.23.0
The FileInfo Interface
The main source for metadata about files is the fs.FileInfo
interface, Listing 14.7. In go1.16
the os.FileInfo
type was aliased to fs.FileInfo
. From this interface we can get the name of the file, the size of the file, the time the file was last modified, and the mode, or permissions, of the file. We can also tell if the file is a directory, or a regular file.
$ go doc fs.FileInfo
package fs // import "io/fs"
type FileInfo interface {
Name() string // base name of the file
Size() int64 // length in bytes for regular files; system-dependent for others
Mode() FileMode // file mode bits
ModTime() time.Time // modification time
IsDir() bool // abbreviation for Mode().IsDir()
Sys() any // underlying data source (can return nil)
}
A FileInfo describes a file and is returned by Stat.
func Stat(fsys FS, name string) (FileInfo, error)
--------------------------------------------------------------------------------
Go Version: go1.23.0
fs.FileInfo
interface.Consider Listing 14.8. We read the contents of the data
directory, and print the mode, size, and name of each file.
func main() {
files, err := os.ReadDir("data")
if err != nil {
log.Fatal(err)
}
fmt.Println("Mode\t\tSize\tName")
for _, file := range files {
info, err := file.Info()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\t%d\t\t%s\n", info.Mode(), info.Size(), info.Name())
}
}
$ go run .
Mode Size Name
drwxr-xr-x 96 .hidden
-rw-r--r-- 31 a.txt
-rw-r--r-- 9 b.txt
drwxr-xr-x 128 e
drwxr-xr-x 96 testdata
--------------------------------------------------------------------------------
Go Version: go1.23.0
fs.FileInfo
to print information about files.Stating a File
The os.ReadDir
function returns a slice of os.DirEntry
values, from which we can get the fs.FileInfo
from, os.DirEntry.Info
. To get the fs.FileInfo
for a single file or directory we can use the os.Stat
function, Listing 14.9.
$ go doc os.Stat
package os // import "os"
func Stat(name string) (FileInfo, error)
Stat returns a FileInfo describing the named file. If there is an error,
it will be of type *PathError.
--------------------------------------------------------------------------------
Go Version: go1.23.0
os.Stat
function.Consider Listing 14.10, which prints the mode, size, and name of the data/a.txt
file.
func main() {
info, err := os.Stat("data/a.txt")
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\t%d\t%s\n", info.Mode(), info.Size(), info.Name())
}
$ go run .
-rw-r--r-- 31 a.txt
--------------------------------------------------------------------------------
Go Version: go1.23.0
os.Stat
to get information about a file.