如何使用通道或 goroutine 将文件夹下的文件移动到子文件夹中

How can I move files under a folder into subfolders by using channel or goroutine

我有一个包含多种类型文件的文件夹(在这个简单的例子中没有子文件夹)。假设它包含 20000 个 .raw 个文件和 20000 个 .jpg 个文件。我需要将 .raw 个文件移动到 raw 文件夹中,将 .jpg 个文件移动到 jpg 文件夹中。所以我厌倦了用golang来解决:

package main

import (
    "flag"
    "fmt"
    "io/fs"
    "io/ioutil"
    "os"
    "runtime"
    "strings"
    "sync"
    "time"
)

func CreateFolder(basePath string, folderName string) {
    os.Mkdir(basePath+"/"+folderName, 0755)
}

func MoveFile(file string, path string, folder string) {
    err := os.Rename(path+"/"+file, path+"/"+folder+"/"+file)
    if err != nil {
        panic(err)
    }
}

func getInfo(a fs.FileInfo, c chan string) {
    if a.IsDir() || strings.HasPrefix(a.Name(), ".") {
        return
    } else {
        c <- a.Name()
    }
}

func dealInfo(path string, typeDict *sync.Map, c chan string) {
    for name := range c {
        sp := strings.Split(name, ".")
        suffix := sp[len(sp)-1]

        if _, ok := typeDict.Load(suffix); ok {
            MoveFile(name, path, suffix)
        } else {
            CreateFolder(path, suffix)
            MoveFile(name, path, suffix)
            typeDict.Store(suffix, 1)
        }
    }
}

func main() {
    runtime.GOMAXPROCS(8)
    var (
        filepath = flag.String("p", "", "default self folder")
    )

    flag.Parse()
    fmt.Println(*filepath)
    fmt.Println("==========")
    if *filepath == "" {
        fmt.Println("No valid folder path")
        return
    } else {
        fileinfos, err := ioutil.ReadDir(*filepath)
        stime := time.Now()
        if err != nil {
            panic(err)
        }
        var typeDict sync.Map
        ch := make(chan string, 20)

        for _, fs := range fileinfos {
            go getInfo(fs, ch)
            go dealInfo(*filepath, &typeDict, ch)
        }
        fmt.Println(time.Since(stime))
    }
}

但它 returns 一个错误:runtime: failed to create new OS thread。我想这是由于脚本创建的 goroutines 太多造成的?但我不知道为什么会发生这种情况,因为我认为 ch := make(chan string, 20) 会限制 goroutine.

的数量

我也试过用wg *sync.WaitGroup,比如:


getInfo(...) // use this func to put all files info into a channel

wg.Add(20)

for i:=0; i<20; i++ {
    go dealInfo(..., &wg)  // this new dealInfo contains wg.Done()
}

wg.Wait()

但这会导致deadlock错误。

我可以知道并行移动文件的最佳方法吗?非常感谢您的帮助!

这可能有效。

但是移动操作取决于操作系统和文件系统。

例如,通过 NFS 并行执行它可能不是最佳选择。你必须检查。

在这种情况下,我将尝试列出文件,发送到通道以供某些 goroutines 执行 (move/rename) 的策略。

goroutines(worker)的数量可以是命令行参数。