golliher
golliher

Reputation: 1417

Getting count of files in directory using Go

How might I get the count of items returned by io/ioutil.ReadDir()?

I have this code, which works, but I have to think isn't the RightWay(tm) in Go.

package main

import "io/ioutil"
import "fmt"

func main() {
    files,_ := ioutil.ReadDir("/Users/dgolliher/Dropbox/INBOX")
    var count int
    for _, f := range files {
        fmt.Println(f.Name())
        count++
    }
    fmt.Println(count)
}

Lines 8-12 seem like way too much to go through to just count the results of ReadDir, but I can't find the correct syntax to get the count without iterating over the range. Help?

Upvotes: 9

Views: 17357

Answers (5)

saeedgnu
saeedgnu

Reputation: 4366

By looking at the code of ioutil.ReadDir

func ReadDir(dirname string) ([]fs.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
    }
    sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
    return list, nil
}

you would realize that it calls os.File.Readdir() then sorts the files.

In case of counting it, you don't need to sort, so you are better off calling os.File.Readdir() directly. You can simply copy and paste this function then remove the sort. But I did find out that f.Readdirnames(-1) is much faster than f.Readdir(-1). Running time is almost half for /usr/bin/ with 2808 items (16ms vs 35ms). So to summerize it in an example:

package main

import (
    "fmt"
    "os"
)

func main() {
    f, err := os.Open(os.Args[1])
    if err != nil {
        panic(err)
    }
    list, err := f.Readdirnames(-1)
    f.Close()
    if err != nil {
        panic(err)
    }
    fmt.Println(len(list))
}

Upvotes: 0

Zombo
Zombo

Reputation: 1

Starting with Go 1.16 (Feb 2021), a better option is os.ReadDir:

package main
import "os"

func main() {
   d, e := os.ReadDir(".")
   if e != nil {
      panic(e)
   }
   println(len(d))
}

os.ReadDir returns fs.DirEntry instead of fs.FileInfo, which means that Size and ModTime methods are omitted, making the process more efficient if you just need an entry count.

https://golang.org/pkg/os#ReadDir

Upvotes: 8

golliher
golliher

Reputation: 1417

Found the answer in http://blog.golang.org/go-slices-usage-and-internals

package main

import "io/ioutil"
import "fmt"

func main() {
    files,_ := ioutil.ReadDir("/Users/dgolliher/Dropbox/INBOX")
    fmt.Println(len(files))
}

Upvotes: 20

Florian Schade
Florian Schade

Reputation: 17

If you wanna get all files (not recursive) you can use len(files). If you need to just get the files without folders and hidden files just loop over them and increase a counter. And please don’t ignore errors

Upvotes: 0

Rod
Rod

Reputation: 1571

ReadDir returns a list of directory entries sorted by filename, so it is not just files. Here is a little function for those wanting to get a count of files only (and not dirs):

func fileCount(path string) (int, error){
    i := 0
    files, err := ioutil.ReadDir(path)
    if err != nil {
        return 0, err
    }
    for _, file := range files {
        if !file.IsDir() { 
            i++
        }
    }
    return i, nil
}

Upvotes: 8

Related Questions