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


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

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

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


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

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
}

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
           }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.