LoginSignup
1
0

More than 1 year has passed since last update.

【fs.FileInfo】ファイルの属性情報【Golang】

Last updated at Posted at 2021-11-28

はじめに

Golangでファイルに関するインターフェースの一つ、fsパッケージについて調べたのでメモ

※2021/2/26 Go1.16より、抽象化されたfsパッケージが実装されたという情報をコメントで頂いたので、記事内容を修正しました。

io/fsパッケージとは

ファイルシステムの基本的なインターフェースです。fsパッケージが実装される以前は各ファイルシステムごとにメソッド名や使い方が異なっていました。

参考程度にfsパッケージの導入によるメリットとして、テストのパフォーマンスや欠陥、テストコードの書きやすさを改善できる点を挙げる記事がありました。

fs.FS

FS(ファイルシステム)の定義は、Openというメソッドが実装されているものとなっています。

io/fs
type FS interface {
    Open(name string) (File, error)
}

FS自体は最小限の構成になっていて、StatFSのような追加のインターフェースを実装することもできます。

io/fs
type StatFS interface {
    FS
    Stat(name string) (FileInfo, error)
}

StatFSはFSに加えてStatのメソッドが実装されているインターフェースです。
他にもいくつか標準で用意されているので公式ドキュメントを参照するとよいです。

fs.FileInfo

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() interface{}   // underlying data source (can return nil)
}

ファイルの情報に関するインターフェース
FileInfo自体はfs.Stat()で得ることができます。

fs.Stat()

io/fs
func Stat(fsys FS, name string) (FileInfo, error)

ルートディレクトリのファイルシステム型とファイル名を指定すれば、そのファイルに関する属性FileInfoを返します。

FSにはOpenが実装されているデータ型やFS型を直接指定するとよいです。

os.DirFS()

FSを直接返してくれる関数
指定したディレクトリをルートとするファイルツリーのファイルシステム(fs.FS)を返します。

os
func DirFS(dir string) fs.FS

FileInfoを取得するサンプル

準備として、任意のディレクトリにtest.txtという空のテキストファイルを作成しました。

package main

import (
    "io/fs"
    "log"
    "os"
)

func main() {
    root := "C:/Users/xxxx/Documents"
    filename := "test.txt"
    fileSystem := os.DirFS(root)

    fileinfo, err := fs.Stat(fileSystem,filename)
    if err != nil {
        log.Fatal(err)
    }
    log.Println(fileSystem) // C:\Users\xxxx\Documents
    log.Println(fileinfo.Name()) // test.txt
    log.Println(fileinfo.Size()) // 0
    log.Println(fileinfo.Mode()) // -rw-rw-rw-
    log.Println(fileinfo.ModTime()) // 2021-11-28 11:47:28.5960394 +0900 JST
    log.Println(fileinfo.IsDir()) // false
    log.Println(fileinfo.Sys()) // &{32 {1214173898 30925826} {1214173898 30925826} {1214173898 30925826} 0 0}
    log.Println(reflect.TypeOf(fileinfo.Sys())) // *syscall.Win32FileAttributeData
}

archive/zipでFileInfoを取得するサンプル

zip.ReaderはOpen()が実装されているため、FS型です。
zip.Readerはzip.OpenReaderで取得できます

準備として、test1.csv, test2.csv, test3.csvを圧縮したtest.zipを用意しました。

import (
    "archive/zip"
    "io/fs"
    "log"
    "reflect"
)

func main() {
    root := "C:/Users/xxxx/Documents/test.zip"
    // get Reader r struct
    r, err := zip.OpenReader(root)
    if err != nil {
        log.Fatal(err)
    }
    defer r.Close()

    filename := "test1.csv"

    fileinfo, err := fs.Stat(r,filename)
    if err != nil {
        log.Fatal(err)
    }
    log.Println(fileinfo.Name()) // test1.csv
    log.Println(fileinfo.Size()) // 432
    log.Println(fileinfo.Mode()) // -rw-rw-rw-
    log.Println(fileinfo.ModTime()) // 2021-11-30 18:25:56 +0000 UTC
    log.Println(fileinfo.IsDir()) // false
    log.Println(fileinfo.Sys()) // &{test1.csv  false 20 20 0 8 2021-11-30 18:25:56 +0000 UTC 37692 21374 3656633017 299 432 299 432 [] 32}
    log.Println(reflect.TypeOf(fileinfo.Sys())) // *zip.FileHeader
}

FileInfo.Sys()はドキュメントには各ファイルシステムのデータソースを返すと書いてあります。
zipではzip.FileHeaderが返されました。

ついでにファイルヘッダーとは、zipファイルの中にあるファイルなどの情報のことです
ファイル自体の中身はファイルエントリと呼ばれます。

最後に

コメントで情報共有いただいた@kechakoさん、ありがとうございました。

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0