[Golang] Split Contents of a Directory into Multiple Sub Directories


Split contents of a directory into multiple sub-directory in Go. For example, if you have a directory with 1,000 files, you split them into 4 sub-directories, each with 300, 300, 300, 100 files inside. You can specify the maximum number of files in each subdirectories.

You can also do this via shell command. See [2].

package main

import (
      "flag"
      "fmt"
      "io/ioutil"
      "os"
      "path"
      "strconv"
)

var maxFilesPerDir = 1500

func getTargetDir(groupCount int, srcDir string) string {
      return path.Join(srcDir, "dir"+strconv.Itoa(groupCount))
}

func createDirIfNotExist(dir string) {
      if _, err := os.Stat(dir); os.IsNotExist(err) {
              err = os.MkdirAll(dir, 0755)
              if err != nil {
                      panic(err)
              }
      }
}

func moveFilesToDir(filesGroup [][]os.FileInfo, srcDir string) {
      for i, group := range filesGroup {
              targetDir := getTargetDir(i, srcDir)
              createDirIfNotExist(targetDir)
              for _, file := range group {
                      filepath := path.Join(srcDir, file.Name())
                      targetFilepath := path.Join(targetDir, file.Name())
                      fmt.Println("move", filepath, "to", targetFilepath)
                      os.Rename(filepath, targetFilepath)
              }
      }
}

func makeFilesGroup(srcDir string) [][]os.FileInfo {
      files, err := ioutil.ReadDir(srcDir)
      if err != nil {
              panic(err)
      }

      count := 0
      var filesGroup [][]os.FileInfo
      filesGroup = append(filesGroup, []os.FileInfo{})
      groupCount := 0
      for _, file := range files {
              if file.Mode().IsRegular() {
                      filesGroup[groupCount] = append(filesGroup[groupCount], file)
                      count++
                      if count == maxFilesPerDir {
                              count = 0
                              filesGroup = append(filesGroup, []os.FileInfo{})
                              groupCount++
                      }
              }
      }

      return filesGroup
}

func main() {
      srcDir := flag.String("src", "", "source dir to split")
      max := flag.Int("max", 1500, "max number of files in split dir")
      flag.Parse()

      maxFilesPerDir = *max
      filesGroup := makeFilesGroup(*srcDir)
      moveFilesToDir(filesGroup, *srcDir)
}

Usage: max means the number of max number of files in sub directory, and src means the path to the directory to split

$ go run splitdir.go -max=500 -src=/path/to/dir/

Tested on: Ubuntu Linux 17.10, Go 1.10.1


References:

[1]
[2]command line - Split contents of a directory into multiple sub directories - Ask Ubuntu