Dosya sistemi taraması nasıl yapılır


104
  1. Bir klasörün yolu verildiğinde, o klasörde bulunan dosyaları tarayan bir işlev yazmam gerekiyor.
  2. Ve sonra o klasördeki dizin yapısını görüntülemem gerekiyor.

2'nin nasıl yapılacağını biliyorum (tarayıcıda görüntülemek için jstree kullanacağım).


2
dizin ağacından yinelemeli olarak geçmeniz gerekiyor mu?
newacct

Yanıtlar:


194

DÜZENLEME : Yeterince kişi hala bu yanıta ulaşıyor, Go1 API için güncelleyeceğimi düşündüm. Bu, filepath.Walk () için çalışan bir örnektir . Orijinal aşağıda.

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

Lütfen filepath.Walk'un dizin ağacını yinelemeli olarak yürüdüğünü unutmayın.

Bu bir örnek çalışma:

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

ORİJİNAL YANIT AŞAĞIDAKİ: Yürüme dosya yolları için arayüz weekly.2011-09-16 itibariyle değişti, bkz http://groups.google.com/group/golang-nuts/msg/e304dd9cf196a218 . Aşağıdaki kod yakın gelecekte GO'nun yayın sürümleri için çalışmayacaktır.

Aslında standart kitaplıkta bunun için bir işlev vardır: 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.Walkbu arada sembolik bağlantıları takip etmiyor.
0xcaff

3
@FrancescoPasa filepath.Walkgeri arama sembolik bağlantılarda (hem dosya hem de dizin) tetiklenecektir. Evet , onları takip etmeyecek, ancak geri arama bir sembolik bağlantıyı tanır ve daha fazla eylemde bulunur, yani filepath.Walkilk önce yolun daha önce ziyaret edilmediğini garanti eden bir takip .
colm.anseo

15

Bir dizindeki dosyalar için dosya bilgilerini elde etmenin bir yolu.

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) ne demektir? Readdir yalnızca dize türünü kabul ettiğinden ve API belgelerine bağlı olarak, bir dize yalnızca NUL olamaz ve başka bir sınırlama olamaz .. ve Readdir'deki "fi" nin dönüş türü nedir, nasıl olur da içinden geçilebilir (bu bir harita mı?) ..
sateayam

@heike: Şimdi API belgelerini içeren gözden geçirilmiş cevabıma bakın. Gördüğünüz gibi, Readdiryöntem parametresi nbir int. If n <= 0, dizindeki Readdirtüm FileInfoöğeleri tek bir dilimde döndürür .
peterSO

@RickSmith: Paketi gör os func (FileMode) IsRegular.
peterSO

1
seçici olmamak, ancak erteleme kapanışınız hata kontrolünden önce gerçekleşmelidir.
Zanven

13

İşte tüm dosya ve dizinlerde özyinelemeli döngü için bir örnek. Eklediğiniz yolun bir dizin olup olmadığını öğrenmek istiyorsanız, sadece "f.IsDir ()" seçeneğini işaretleyin.

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

Bir işlevi kopyalayıp yapıştırdınız mı? mainYöntem olmamalıdır ([]string, error)args ve birlikte bir şeyler yapmak gerekiyor err. Cevap verildiği sırada geçerli olmadığı sürece? Daha yeni sürümlerde kesinlikle bir derleme hatası. Aksi takdirde, çok faydalı, teşekkürler.
Steve


4

Go standard paketi ioutilbu durum senaryosu için yerleşik işleve sahiptir, aşağıdaki örneğe bakın

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

"Walk sembolik bağları izlemez ", bu nedenle ioutil.ReadDir'i önerdiğim bir işlev yazmak istiyorsanız, unutmayın . Kendi kıyaslama testim , filepath.Glob'dan daha hızlı ve daha az bellek yoğun olduğunu gösterdi .

Ek olarak, ioutil.ReadDirdosyaları temel dize karşılaştırması ( strA > strB) kullanarak taban adına göre sıralar . Bir devops adamı olarak, genellikle ters sayısal bir karşılaştırma yaparak dir isimlerini sıralarım (örneğin en son derleme). Bu da sizin durumunuzsa, os.ReadDir'i doğrudan ioutil.ReadDirçağırmak ( bunu kapakların altında çağırmaktır) ve sıralamayı kendiniz yapmak daha iyidir .

İşte ReadDirSayısal sıralama ile parçanın bir örneği :

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

Aramayı tam olarak kullanabilmek için burada currying işlevi yapmak isteyebilirsiniz.

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
           }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.