Come eseguire la scansione del file system


104
  1. Ho bisogno di scrivere una funzione che, quando viene indicato il percorso di una cartella, scansiona i file radicati in quella cartella.
  2. E poi ho bisogno di visualizzare la struttura della directory in quella cartella.

So come fare 2 (userò jstree per visualizzarlo nel browser).


2
ne hai bisogno per passare attraverso l'albero delle directory in modo ricorsivo?
newacct

Risposte:


194

EDIT : abbastanza persone hanno ancora risposto a questa risposta, che ho pensato di aggiornarlo per l'API Go1. Questo è un esempio funzionante di filepath.Walk () . L'originale è sotto.

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

Si noti che filepath.Walk percorre l'albero delle directory in modo ricorsivo.

Questo è un esempio eseguito:

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

SEGUE RISPOSTA ORIGINALE: L'interfaccia per i percorsi dei file a piedi è cambiata a partire dalla settimana 2011-09-16, vedere http://groups.google.com/group/golang-nuts/msg/e304dd9cf196a218 . Il codice seguente non funzionerà per le versioni di rilascio di GO nel prossimo futuro.

In realtà c'è una funzione nella libreria standard solo per questo: 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.Walknon segue i collegamenti simbolici a proposito.
0xcaff

3
Il filepath.Walkcallback di @FrancescoPasa verrà attivato sui collegamenti simbolici (sia file che directory). Sì, non li seguirà , ma il callback riconosce un collegamento simbolico e intraprende ulteriori azioni, ovvero un follow-up filepath.Walkassicurandosi prima che il percorso non sia già stato visitato.
colm.anseo

15

Ecco un modo per ottenere informazioni sui file per i file in una directory.

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: cosa significa Readdir (-1)? poiché Readdir accetta solo il tipo di stringa e, in base alla documentazione API, una stringa non può essere NUL e nessun'altra limitazione .. e qual è il tipo di ritorno di "fi" nella Readdir come mai può essere percorsa (è una mappa?) ..
sateayam

@heike: vedi la mia risposta rivista, che ora include la documentazione API. Come puoi vedere, il Readdirparametro del metodo è nun file int. If n <= 0, Readdirrestituisce tutti i FileInfodalla directory in una singola slice.
peterSO

@RickSmith: vedi pacchetto os func (FileMode) IsRegular.
peterSO

1
non essere pignoli, ma la tua chiusura differita dovrebbe avvenire prima del controllo degli errori.
Zanven

13

Ecco un esempio per scorrere in modo ricorsivo tutti i file e le directory. Nota che se vuoi sapere se il percorso che stai aggiungendo è una directory, seleziona "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)
    }
}

Hai copiato e incollato una funzione? Il mainmetodo non dovrebbe avere ([]string, error)argomenti e devi fare qualcosa con err. A meno che al momento della risposta non fosse valido? Sicuramente un errore di compilazione nelle versioni più recenti. Altrimenti, molto utile, grazie.
Steve


4

Il pacchetto standard Go ioutilha una funzione incorporata per questo caso, vedere l'esempio sotto

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

Nota che "Walk non segue link simbolici" quindi se stai cercando di scrivere una funzione che lo fa, ti consiglio ioutil.ReadDir . Il mio test di benchmark ha mostrato che è più veloce e richiede meno memoria di filepath.Glob .

Inoltre, ioutil.ReadDirordina i file per nome di base utilizzando il confronto di stringhe di base ( strA > strB). Come ragazzo devops, generalmente ordino i nomi delle directory facendo un confronto numerico inverso (ad esempio, l'ultima build prima). Se questo è anche il tuo caso, è meglio chiamare direttamente os.ReadDir (lo ioutil.ReadDirchiama sotto le coperte) e fare l'ordinamento da soli.

Ecco un esempio della ReadDirparte con Ordinamento numerico:

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

Potresti voler eseguire la funzione curry qui, in modo da poter utilizzare appieno la ricerca

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
           }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.