如何使用通道或 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)的数量可以是命令行参数。
我有一个包含多种类型文件的文件夹(在这个简单的例子中没有子文件夹)。假设它包含 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)的数量可以是命令行参数。