How to perform file system scanning

FileGoDirectory

File Problem Overview


  1. I need to write a function which when given the path of a folder scans the files rooted at that folder.
  2. And then I need to display the directory structure at that folder.

I know how to do 2 (I am going to use jstree to display it in the browser).

File Solutions


Solution 1 - File

EDIT FOR 1.16: Enough people still hit this answer, that I thought I'd update it for Go 1.16.

The function filepath.WalkDir introduced in Go 1.16 has better performance than filepath.Walk mentioned in the previous edit. Here's a working example:

package main

import (
	"flag"
	"fmt"
	"io/fs"
	"path/filepath"
)

func visit(path string, di fs.DirEntry, err error) error {
	fmt.Printf("Visited: %s\n", path)
	return nil
}

func main() {
	flag.Parse()
	root := flag.Arg(0)
	err := filepath.WalkDir(root, visit)
	fmt.Printf("filepath.WalkDir() returned %v\n", err)
}

EDIT: Enough people still hit this answer, that I thought I'd update it for the Go1 API. This is a working example of filepath.Walk(). The original is below.

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

Please note that filepath.Walk walks the directory tree recursively.

This is an example 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>

ORIGINAL ANSWER FOLLOWS: The interface for walking file paths has changed as of weekly.2011-09-16, see http://groups.google.com/group/golang-nuts/msg/e304dd9cf196a218. The code below will not work for release versions of GO in the near future.

There's actually a function in the standard lib just for this: 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)
}

Solution 2 - File

Here's a way to obtain file information for the files in a 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")
		}
	}
}

Solution 3 - File

Here is an example to loop through all files and directories recursively. Note that if you want to know whether the path you're appending is a directory just check "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)
	}
}

Solution 4 - File

Package github.com/kr/fs provides a Walker with a very interesting API.

Solution 5 - File

Go standard package ioutil has built in function for this case scenario see below example

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

Solution 6 - File

Note that "Walk does not follow symbolic links" so if you are looking to write a function that does that I recommend ioutil.ReadDir. My own benchmark test showed that it is faster and less memory intensive than filepath.Glob.

Additionally, ioutil.ReadDir is sorting files by basename using basic string comparison (strA > strB). As a devops guy, I generally sort dir names by doing a reverse numerical comparison (latest build first for example). If that is also your case then it is better to call os.ReadDir directly (ioutil.ReadDir is calling this under the covers) and do the sorting yourself.

Here is an example of the ReadDir part with Numerical sort:

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

Solution 7 - File

You might want to do function currying here, so that you are able to fully utilise the search

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionchinmayView Question on Stackoverflow
Solution 1 - FilelaslowhView Answer on Stackoverflow
Solution 2 - FilepeterSOView Answer on Stackoverflow
Solution 3 - FileFrancoisView Answer on Stackoverflow
Solution 4 - FileMostafaView Answer on Stackoverflow
Solution 5 - FileJimmy Obonyo AborView Answer on Stackoverflow
Solution 6 - FileDavidGambaView Answer on Stackoverflow
Solution 7 - FileswayamrainaView Answer on Stackoverflow