Comment effectuer une analyse du système de fichiers

104
  1. J'ai besoin d'écrire une fonction qui, lorsqu'on lui donne le chemin d'un dossier, analyse les fichiers enracinés dans ce dossier.
  2. Et puis j'ai besoin d'afficher la structure de répertoires dans ce dossier.

Je sais comment faire 2 (je vais utiliser jstree pour l'afficher dans le navigateur).

Chinmay
la source
2
en avez-vous besoin pour parcourir l'arborescence des répertoires de manière récursive?
newacct

Réponses:

194

EDIT : Assez de gens ont encore répondu à cette réponse, que j'ai pensé la mettre à jour pour l'API Go1. Ceci est un exemple fonctionnel de filepath.Walk () . L'original est ci-dessous.

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

Veuillez noter que filepath.Walk parcourt l'arborescence des répertoires de manière récursive.

Ceci est un exemple d'exécution:

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

RÉPONSE ORIGINALE SUIT: L'interface pour parcourir les chemins de fichiers a changé à partir du 16 septembre 2011, voir http://groups.google.com/group/golang-nuts/msg/e304dd9cf196a218 . Le code ci-dessous ne fonctionnera pas pour les versions de GO dans un proche avenir.

Il y a en fait une fonction dans la bibliothèque standard juste pour cela: 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
la source
1
filepath.Walkne suit pas les liens symboliques d'ailleurs.
0xcaff
3
Le filepath.Walkrappel @FrancescoPasa sera déclenché sur les liens symboliques (fichier et répertoire). Oui, il ne les suivra pas, mais le callback reconnaît un lien symbolique et prend des mesures supplémentaires, c'est-à-dire un suivi filepath.Walkassurant d'abord que le chemin n'a pas déjà été visité.
colm.anseo
15

Voici un moyen d'obtenir des informations sur les fichiers d'un répertoire.

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
la source
@peterSO: que signifie Readdir (-1)? comme le Readdir n'accepte que le type de chaîne, et en fonction de la documentation de l'API, une chaîne ne peut pas être NUL, et aucune autre limitation .. et quel est le type de retour du "fi" dans le Readdir comment se fait-il qu'il puisse être parcouru (est-ce une carte?) ..
sateayam
@heike: Voir ma réponse révisée, qui comprend désormais la documentation de l'API. Comme vous pouvez le voir, le Readdirparamètre de méthode est nun int. Si n <= 0, Readdirrenvoie tous les FileInfodu répertoire en une seule tranche.
peterSO
@RickSmith: Voir le package os func (FileMode) IsRegular.
peterSO
1
pour ne pas être pointilleux, mais votre clôture différée doit avoir lieu avant le contrôle d'erreur.
Zanven
13

Voici un exemple pour parcourir tous les fichiers et répertoires de manière récursive. Notez que si vous voulez savoir si le chemin que vous ajoutez est un répertoire, cochez simplement "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)
    }
}
François
la source
Avez-vous copié et collé une fonction? La mainméthode ne devrait pas avoir d' ([]string, error)arguments et vous devez faire quelque chose avec err. À moins qu'au moment de répondre, il était valide? Certainement une erreur de compilation dans les versions plus récentes. Sinon, très utile, merci.
Steve
7

Le package github.com/kr/fsfournit une WalkerAPI très intéressante.

Mostafa
la source
4

Le package standard Go ioutila une fonction intégrée pour ce scénario de cas, voir l'exemple ci-dessous

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
la source
1

Notez que "Walk ne suit pas les liens symboliques" donc si vous cherchez à écrire une fonction qui fait cela, je recommande ioutil.ReadDir . Mon propre test de référence a montré qu'il est plus rapide et moins gourmand en mémoire que filepath.Glob .

De plus, ioutil.ReadDirtrie les fichiers par nom de base à l'aide de la comparaison de chaînes de base ( strA > strB). En tant que développeur devops, je trie généralement les noms de répertoires en faisant une comparaison numérique inversée (la dernière version en premier par exemple). Si c'est également votre cas, il est préférable d'appeler directement os.ReadDir (il l' ioutil.ReadDirappelle sous les couvertures) et de faire le tri vous-même.

Voici un exemple de la ReadDirpièce avec tri numérique:

// 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
la source
0

Vous voudrez peut-être faire le currying des fonctions ici, afin de pouvoir utiliser pleinement la recherche

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
la source