🦖

【Go】Goでファイルのサイズを取得する方法

2023/09/10に公開

背景

  • Go言語の勉強がてら「ls」コマンドを再現していました.
  • そこで、ファイルのサイズを取得する際に少し困ったことがありました.
  • それは「io/ioutil」パッケージが非推奨になっていることです
  • 「io/ioutil」を使用すれば、ファイルのサイズは容易に取得出来ます
package main

import "fmt"
import "io/ioutil"

func main() {
    files, _ := ioutil.ReadDir("./")
    for _, f := range files {
        fmt.Println(f.Size())
    }
}
  • なので、今回は「os」パッケージを使用してファイルサイズを取得する方法を紹介します

結論

	items, _ := os.ReadDir("./")
	for _, item := range items {
		// ファイルの情報を取得
		file_info, _ := item.Info()
		file_size := file_info.Size()
	}

解説

ファイルの情報を取得

  • osの ReadDir を使用して現在のディレクトリ("./")配下のファイルの情報を取得します
items, err := os.ReadDir("./")

ReadDirは何を返してくれるのか

  • ReadDirは []DirEntry 型の値を返却してくれます
dir.go
func ReadDir(name string) ([]DirEntry, error) {
	f, err := Open(name)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	dirs, err := f.ReadDir(-1)
	sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() })
	return dirs, err
}

[]DirEntryについて

  • []DirEntryfs.DirEntry という型で定義されています
dir.go
type DirEntry = fs.DirEntry
  • DirEntry を追いかけてみます
fs.go
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)
}
  • Info() に注目します FileInfo を返してくれるそうですね

FileInfoは何を返してくれるのか

  • 次は FileInfo を追いかけてみます
  • サイズを返してくれそうなところを見つけました !
fs.go
// A FileInfo describes a file and is returned by Stat.
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)
}

どういうことか整理する

  • os.ReadDirで取得した値(ファイルひとつひとつ)は Info() を持っている
  • Info()size を持っているということですね
  • なので、下記のように取り出してあげれば取得出来そうです
	items, _ := os.ReadDir("./")
	for _, item := range items {
		// ファイルの情報を取得
		file_info, _ := item.Info()
		file_size := file_info.Size()
	}

Discussion