Cara melakukan pemindaian sistem file

104
  1. Saya perlu menulis fungsi yang ketika diberi jalur folder memindai file yang di-rooting di folder itu.
  2. Dan kemudian saya perlu menampilkan struktur direktori di folder itu.

Saya tahu bagaimana melakukan 2 (saya akan menggunakan jstree untuk menampilkannya di browser).

chinmay
sumber
2
apakah Anda memerlukannya untuk menelusuri pohon direktori secara rekursif?
newacct

Jawaban:

194

EDIT : Cukup banyak orang yang masih mendapatkan jawaban ini, sehingga saya pikir saya akan memperbaruinya untuk Go1 API. Ini adalah contoh kerja filepath.Walk () . Yang asli ada di bawah.

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)
}

Harap dicatat bahwa filepath.Walk berjalan di pohon direktori secara rekursif.

Ini adalah contoh run:

$ 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>

IKUTI JAWABAN ASLI: Antarmuka untuk jalur file berjalan telah berubah mulai mingguan.2011-09-16, lihat http://groups.google.com/group/golang-nuts/msg/e304dd9cf196a218 . Kode di bawah ini tidak akan berfungsi untuk versi rilis GO dalam waktu dekat.

Sebenarnya ada fungsi di lib standar hanya untuk ini: 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)
}
laslowh.dll
sumber
1
filepath.Walktidak mengikuti symlink.
0xcaff
3
filepath.WalkCallback @FrancescoPasa akan dipicu di symlink (file dan direktori). Ya itu tidak akan mengikuti mereka, tetapi callback mengenali symlink dan mengambil tindakan lebih lanjut yaitu tindak lanjut yang filepath.Walkmemastikan terlebih dahulu bahwa jalan tersebut belum dikunjungi.
colm.anseo
15

Berikut adalah cara mendapatkan informasi file untuk file dalam direktori.

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
sumber
@peterSO: apa arti Readdir (-1)? karena Readdir hanya menerima tipe string, dan berdasarkan dokumentasi API, string hanya tidak boleh NUL, dan tidak ada batasan lain .. dan apa tipe kembalian dari "fi" di Readdir kenapa bisa berjalan melalui (apakah itu peta?) ..
sateayam
@heike: Lihat jawaban saya yang telah direvisi, yang sekarang menyertakan dokumentasi API. Seperti yang Anda lihat, Readdirparameter metode adalah nsuatu int. Jika n <= 0, Readdirmengembalikan semua FileInfodari direktori dalam satu irisan.
peterSO
@RickSmith: Lihat paket os func (FileMode) IsRegular.
peterSO
1
tidak pilih-pilih tetapi penundaan Anda harus terjadi sebelum pemeriksaan kesalahan.
Zanven
13

Berikut adalah contoh untuk mengulang semua file dan direktori secara rekursif. Perhatikan bahwa jika Anda ingin mengetahui apakah jalur yang Anda tambahkan adalah direktori, cukup centang "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)
    }
}
Francois
sumber
Apakah Anda menyalin dan menempelkan suatu fungsi? The mainmetode harus tidak memiliki ([]string, error)args dan Anda perlu melakukan sesuatu dengan err. Kecuali pada saat menjawab itu valid? Jelas kesalahan kompilasi di versi yang lebih baru. Jika tidak, sangat berguna, terima kasih.
Steve
7

Paket github.com/kr/fsmenyediakan WalkerAPI yang sangat menarik.

Mostafa
sumber
4

Paket standar Go ioutilmemiliki fungsi bawaan untuk skenario kasus ini, lihat contoh di bawah

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())
    }
}
Jimmy Obonyo Abor
sumber
1

Perhatikan bahwa "Walk tidak mengikuti tautan simbolik" jadi jika Anda ingin menulis fungsi yang melakukannya, saya sarankan ioutil.ReadDir . Tes benchmark saya sendiri menunjukkan bahwa itu lebih cepat dan lebih sedikit memori intensif daripada filepath. Glob . .

Selain itu, ioutil.ReadDirmengurutkan file berdasarkan nama dasar menggunakan perbandingan string dasar ( strA > strB). Sebagai seorang devops, saya biasanya mengurutkan nama dir dengan melakukan perbandingan numerik terbalik (build terbaru pertama misalnya). Jika itu juga kasus Anda, maka lebih baik memanggil os.ReadDir secara langsung (ioutil.ReadDir memanggil ini di bawah sampul) dan melakukan penyortiran sendiri.

Berikut adalah contoh ReadDirbagian dengan Urutan numerik:

// 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
}
DavidG
sumber
0

Anda mungkin ingin melakukan fungsi kari di sini, sehingga Anda dapat memanfaatkan pencarian sepenuhnya

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
           }
}
swayamraina
sumber