write ahead log

ロールフォワード用

golangでファイル・ディレクトリを操作する

ちょっとしたツールを作るのにも, DBを使うのが面倒な時にもファイル操作は便利.

サンプルコードの実行にはosパッケージをインポートしてください. (Printしてるものには当然fmtも)

import (
    "os"
    "path/filepath" //ファイルパス操作の時は
)
ディレクトリを作る
// パーミッション0777でfooを作成
if err := os.Mkdir("foo", 0777); err != nil {
    panic(err)
}
サブディレクトリも作る

サブディレクトリもまとめて作りたい時

// パーミッション0777でhoge/fugaを作成(サブディレクトリもまとめて作る)
if err := os.MkdirAll("hoge/fuga", 0777); err != nil {
    panic(err)
}
ファイル・ディレクトリの名前変更

fooをbarに変更

if err := os.Rename("foo", "bar"); err != nil {
    panic(err)
}
ファイル・ディレクトリの移動

fooの下のtest.txtをbarへ移動.こちらもRenameを使う(どうなんだろう,これ)

if err := os.Rename("foo/test.txt", "bar/test.txt"); err != nil {
    panic(err)
}
ファイル・ディレクトリの権限変更

コマンドのchmodと変わらないですね.

if err := os.Chmod("foo", 0666); err != nil {
    panic(err)
}
ファイル・ディレクトリの削除

下記では中身のあるディレクトリは消せません(rmdirと同じですね)

if err := os.Remove("foo"); err != nil {
    panic(err)
}
ファイル・ディレクトリの削除(中のファイルごと)

これで中身があろうと消せます.

if err := os.RemoveAll("foo"); err != nil {
    panic(err)
}
ファイル・ディレクトリの存在確認

statでエラーが無いかで判断するのが良いようです.

_, err := os.Stat("foo.txt")
if err == nil {
    fmt.Println("あった")
} else {
    fmt.Println("なかった")
}

もうちょっと複雑な操作

ここから先はfilepathもインポートしてください. (Printしてるものには当然fmtも)

import (
    "os"
    "path/filepath"
)
指定ディレクトリ下のファイル・ディレクトリ一覧の取得

filepath.Walkを使います.
これはちょっとややこしいので全部書きます.
walk_funcは匿名関数の方がわかりやすい場合もあるかもしれません.

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func walk_func(path string, info os.FileInfo, err error) error {
    // ディレクトリか判断
    if info.IsDir() {
        // hoge/foo以下は無視する
        if path == "hoge/foo" {
            // 無視するときはfilepath.SkipDirを戻す
            return filepath.SkipDir
        }
    }
    // パスを印字
    fmt.Println(path)
    // 普通はnilを戻す
    return nil
}

func main() {
    root_dir := "."
    err := filepath.Walk(root_dir, walk_func)

    if err != nil {
        panic(err)
    }
}

実行結果

ディレクトリが荒れててちょっとわかりづらいですが.

twinbird@:~/go/src/file_operate$ ./file_operate 
.
bar
bar/test.txt
blog.txt
file_operate
foo
hoge
sample.go
twinbird@:~/go/src/file_operate$ tree .
.
├── bar
│   └── test.txt
├── blog.txt
├── file_operate
├── foo
├── hoge
│   └── foo
│       └── test2.txt
└── sample.go

ちょっと解説入れると

  • filepath.Walkはディレクトリやファイルが見つかるたびにwalk_funcをコールバックで呼び出すことになります.
  • コールバックのinfoにはファイル情報が入っているので参照できます.
  • コールバックの戻り値にfilepath.SkipDirを使えば,走査中の配下のディレクトリは無視するようです.基本はnilを戻します.

ファイルパスの操作

ファイル操作するときにはファイルパスの操作もセットみたいなもんでしょう.

絶対パスを取得する

filepath.Absを使います.

abs_path, err := filepath.Abs(".")
if err != nil {
    panic(err)
}
fmt.Println(abs_path)

実行結果

/home/twinbird/go/src/file_operate
ファイル名を取得する
base_path := filepath.Base(`C:\Users\IMAI\Desktop\test\a.txt`)
fmt.Println(base_path)

実行結果

a.txt
ファイルパスを連結する
base_path := `C:\Users\IMAI\Desktop\test`
file_path := "a.txt"
joined_path := filepath.Join(base_path, file_path)
fmt.Println(joined_path)

実行結果

C:\Users\IMAI\Desktop\test\a.txt
拡張子を取得する
file_path := "a.txt"
ext := filepath.Ext(file_path)
fmt.Println(ext)

実行結果

.txt