ファイルシステムスキャンを実行する方法


104
  1. フォルダーのパスを指定すると、そのフォルダーをルートとするファイルをスキャンする関数を作成する必要があります。
  2. そして、そのフォルダのディレクトリ構造を表示する必要があります。

私は2の方法を知っています(jstreeを使用してブラウザーに表示します)。


2
ディレクトリツリーを再帰的に移動するために必要ですか?
newacct 2011

回答:


194

編集:十分な数の人々がまだこの答えにぶつかりました。私はGo1 APIのためにそれを更新するつもりでした。これはfilepath.Walk()の実際の例です。オリジナルは以下です。

package main

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

func visit(path string, f os.FileInfo, err error) error {
  fmt.Printf("Visited: %s\n", path)
  return nil
} 


func main() {
  flag.Parse()
  root := flag.Arg(0)
  err := filepath.Walk(root, visit)
  fmt.Printf("filepath.Walk() returned %v\n", err)
}

filepath.Walkはディレクトリツリーを再帰的にウォークすることに注意してください。

これは実行例です:

$ mkdir -p dir1/dir2
$ touch dir1/file1 dir1/dir2/file2
$ go run walk.go dir1
Visited: dir1
Visited: dir1/dir2
Visited: dir1/dir2/file2
Visited: dir1/file1
filepath.Walk() returned <nil>

の回答は次のとおりですファイルパスを歩くためのインターフェイスがweekly.2011-09-16で変更されました。http://groups.google.com/group/golang-nuts/msg/e304dd9cf196a218を参照してください。以下のコードは、近い将来のリリースバージョンのGOでは機能しません。

実際には、標準のlibにfilepath.Walkという関数があります。

package main

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

type visitor int

// THIS CODE NO LONGER WORKS, PLEASE SEE ABOVE
func (v visitor) VisitDir(path string, f *os.FileInfo) bool {
    println(path)
    return true
} 

func (v visitor) VisitFile(path string, f *os.FileInfo) {
    println(path)
}

func main() {
    root := flag.Arg(0)
    filepath.Walk(root, visitor(0), nil)
}

1
filepath.Walkちなみにシンボリックリンクをたどりません。
0xcaff 2016年

3
@FrancescoPasa filepath.Walkコールバックはシンボリックリンク(ファイルとディレクトリの両方)でトリガーされます。はい、それはそれらに従いませんが、コールバックはシンボリックリンクを認識filepath.Walkし、パスがまだ訪問されていないことを最初に確認するフォローアップ、つまりフォローアップを行います。
colm.anseo 2017年

15

これは、ディレクトリ内のファイルのファイル情報を取得する方法です。

package main

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

func main() {
    dirname := "." + string(filepath.Separator)
    d, err := os.Open(dirname)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    defer d.Close()
    fi, err := d.Readdir(-1)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    for _, fi := range fi {
        if fi.Mode().IsRegular() {
            fmt.Println(fi.Name(), fi.Size(), "bytes")
        }
    }
}

@peterSO:Readdir(-1)の意味は?Readdirは文字列型のみを受け入れるため、APIドキュメントに基づいて、文字列はNULのみにすることはできず、その他の制限もありません。Readdirの「fi」の戻り値の型とは何ですか? (地図ですか?)..
sateayam 2013

@heike:私の改訂された回答をご覧ください。これには、APIドキュメントが含まれています。あなたが見ることができるように、Readdirメソッドのパラメータがあります。の場合、ディレクトリのすべてのを1つのスライスで返します。nintn <= 0ReaddirFileInfo
peterSO 2013

@RickSmith:パッケージを参照してくださいos func (FileMode) IsRegular
peterSO 2013

1
うるさいことではありませんが、エラーチェックの前に遅延クローズを行う必要があります。
Zanven

13

以下は、すべてのファイルとディレクトリを再帰的にループする例です。追加するパスがディレクトリかどうかを知りたい場合は、「f.IsDir()」を確認してください。

package main

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

func main() {
    searchDir := "c:/path/to/dir"

    fileList := []string{}
    err := filepath.Walk(searchDir, func(path string, f os.FileInfo, err error) error {
        fileList = append(fileList, path)
        return nil
    })

    for _, file := range fileList {
        fmt.Println(file)
    }
}

関数をコピーして貼り付けましたか?main方法は持つべきではない([]string, error)引数をし、あなたが何かをする必要がありerr。回答時を除いて、それは有効でしたか?最近のバージョンでは間違いなくコンパイルエラーです。それ以外の場合、非常に便利です、ありがとうございます。
スティーブ


4

Goの標準パッケージにioutilは、このケースシナリオ用の組み込み関数があります。以下の例を参照してください。

func searchFiles(dir string) { // dir is the parent directory you what to search
    files, err := ioutil.ReadDir(dir)
    if err != nil {
        log.Fatal(err)
    }

    for _, file := range files {
        fmt.Println(file.Name())
    }
}

1

「ウォークはシンボリックリンクをたどらない」ことに注意してください。そのため、そのような関数を記述したい場合は、ioutil.ReadDirをお勧めします。私自身のベンチマークテストでは、filepath.Globよりも高速でメモリ使用量が少ないことがわかりました

さらに、ioutil.ReadDirは、基本的な文字列比較(strA > strB)を使用して、ファイルをベース名でソートします。開発者として、私は通常、逆の数値比較(たとえば、最初に最新のビルドを行う)を行うことによって、dir名をソートします。それがあなたのケースでもある場合は、os.ReadDirを直接呼び出して(ioutil.ReadDirこれを内部で呼び出しています)、自分で並べ替えを行うことをお勧めします。

以下は、ReadDir数値ソートを使用したパーツの例です。

// ReadDirNumSort - Same as ioutil/ReadDir but uses returns a Numerically
// Sorted file list.
//
// Taken from https://golang.org/src/io/ioutil/ioutil.go
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Modified Sort method to use Numerically sorted names instead.
// It also allows reverse sorting.
func ReadDirNumSort(dirname string, reverse bool) ([]os.FileInfo, error) {
    f, err := os.Open(dirname)
    if err != nil {
        return nil, err
    }
    list, err := f.Readdir(-1)
    f.Close()
    if err != nil {
        return nil, err
    }
    if reverse {
        sort.Sort(sort.Reverse(byName(list)))
    } else {
        sort.Sort(byName(list))
    }
    return list, nil
}

// byName implements sort.Interface.
type byName []os.FileInfo

func (f byName) Len() int      { return len(f) }
func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
func (f byName) Less(i, j int) bool {
    nai, err := strconv.Atoi(f[i].Name())
    if err != nil {
        return f[i].Name() < f[j].Name()
    }
    naj, err := strconv.Atoi(f[j].Name())
    if err != nil {
        return f[i].Name() < f[j].Name()
    }
    return nai < naj
}

0

ここで関数カリーを実行すると、検索を十分に活用できます

func visit(files *[]string) filepath.WalkFunc {
    return func (path string, info os.FileInfo, err error) error {
               // maybe do this in some if block
               *files = append(*files, path)
               return nil
           }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.