it-swarm.com.de

Wie führt man ein Dateisystem-Scan in Golang durch?

  1. Ich muss eine Funktion schreiben, die, wenn der Pfad eines Ordners angegeben wird, die in diesem Ordner verwurzelten Dateien durchsucht. 
  2. Und dann muss ich die Verzeichnisstruktur in diesem Ordner anzeigen. 

Ich weiß, wie man 2 macht (ich werde Jstree verwenden, um es im Browser anzuzeigen). 

Bitte helfen Sie mir mit Teil 1, wie/wo ich anfangen soll, eine solche Funktion in go zu schreiben.

95
chinmay

EDIT: Es treffen immer noch genügend Leute auf diese Antwort, sodass ich dachte, ich würde sie für die Go1-API aktualisieren. Dies ist ein funktionierendes Beispiel für filepath.Walk () . Das Original ist unten.

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

Bitte beachten Sie, dass filepath.Walk den Verzeichnisbaum rekursiv durchläuft.

Dies ist ein Beispiellauf:

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

URSPRÜNGLICHE ANTWORT FOLGT: Die Oberfläche für das Gehen von Dateipfaden wurde zum wöchentlichen 16.09.2011 geändert, siehe http: // groups .google.com/group/golang-nuts/msg/e304dd9cf196a218 . Der folgende Code wird in naher Zukunft nicht für Release-Versionen von GO funktionieren.

Es gibt tatsächlich eine Funktion in der Standard-Bibliothek, nur dafü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)
}
189
laslowh

Hier erhalten Sie eine Möglichkeit, Dateiinformationen für die Dateien in einem Verzeichnis abzurufen.

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")
        }
    }
}
15
peterSO

Hier ist ein Beispiel, um alle Dateien und Verzeichnisse rekursiv durchzugehen. Wenn Sie wissen möchten, ob der angehängte Pfad ein Verzeichnis ist, überprüfen Sie einfach "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)
    }
}
12
Francois

Package github.com/kr/fs bietet eine Walker mit einer sehr interessanten API.

6
Mostafa

Das Standardpaket ioutil verfügt über eine integrierte Funktion für dieses Fall-Szenario 

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

Beachten Sie, dass "Walk folgt nicht symbolischen Links". Wenn Sie also eine Funktion schreiben möchten, die dies tut, empfehle ich ioutil.ReadDir . Mein eigener Benchmark-Test hat gezeigt, dass er schneller und weniger speicherintensiv ist als filepath.Glob .

Darüber hinaus sortiert ioutil.ReadDir Dateien nach Basisnamen unter Verwendung des grundlegenden Zeichenfolgenvergleichs (strA > strB). Als Devops-Typ sortiere ich im Allgemeinen Verzeichnisnamen durch einen umgekehrten numerischen Vergleich (neueste Version zuerst). Wenn dies auch Ihr Fall ist, ist es besser, os.ReadDir direkt anzurufen (ioutil.ReadDir ruft dies unter den Deckblättern an) und die Sortierung selbst vorzunehmen.

Hier ist ein Beispiel für den ReadDir-Teil mit numerischer Sortierung:

// 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
}
1
DavidG

https://github.com/030/go-find

package main

import (
    "log"

    find "github.com/030/go-find/find"
)

func main() {
    path, err := find.File("/home/user/go/src/github.com/030", "find.go")
    if err != nil {
        log.Fatal(err)
    }
}

kehrt zurück

/home/user/go/src/github.com/030/go-find/find/find.go
0
030