拷,1点半了,写太晚了。 总之是个好东东。直接上代码了,不解释。
/* 批量替换和转移目录的东东 遍历指定目录(包含子目录),对于指定扩展名的文件, 查找并替换文件内容中的指定字符串,并 将其输出到新的目录(包含子目录)下。原文件内容不变。 至于其它非指定的文件,也一并复制一份到新目录下。 使用Josn作为配置文件. Author:XiongChuanLiang Date:2015-10-23 Linux 配置示例: { "sourcedir":"/home/xcl/test/t1/","destdir":"/home/xcl/test/t2/","fileext":[".go",".conf"],"replacewhere":[{ "findwhat":"V9","replacewith":"V10" },{ "findwhat":"172.18.1.101","replacewith":"192.168.1.101" }] } 注意: sourcedir与destdir 配置时要对整齐,且最后要加"/". */ package main import ( "bufio" "encoding/json" "fmt" "io" "io/IoUtil" "os" "path/filepath" "runtime" "strings" "sync" "time" ) const ( flagFile = "flag.json" ) type RWhere struct { FindWhat string `json:"findwhat"` ReplaceWith string `json:"replacewith"` } type ReplaceConf struct { SourceDir string `json:"sourcedir"` DestDir string `json:"destdir"` FileExtension []string `json:"fileext"` ReplaceWhere []RWhere `json:"replacewhere"` CaseSensitive bool `json:"casesensitive,omitempty"` } var repConf ReplaceConf var repReplacer *strings.Replacer var extFileNum,otherFileNum int var maxGoroutines int func init() { maxGoroutines = 10 } func main() { now := time.Now() runtime.GOMAXPROCS(runtime.Numcpu()) parseJsonFile() findSourceFiles(repConf.SourceDir) end_time := time.Now() var dur_time time.Duration = end_time.Sub(now) fmt.Printf("elapsed %f seconds\n",dur_time.Seconds()) fmt.Println("处理统计") fmt.Println(" 处理指定类型文件:",extFileNum) fmt.Println(" 处理其它文件:",otherFileNum) } func findSourceFiles(dirname string) { waiter := &sync.WaitGroup{} fmt.Println("dirname:",dirname) filepath.Walk(dirname,sourceWalkFunc(waiter)) waiter.Wait() } func sourceWalkFunc(waiter *sync.WaitGroup) func(string,os.FileInfo,error) error { return func(path string,info os.FileInfo,err error) error { if err == nil && info.Size() > 0 && !info.IsDir() { if runtime.NumGoroutine() > maxGoroutines { parseFile(path,nil) } else { waiter.Add(1) go parseFile(path,func() { waiter.Done() }) } } else { fmt.Println("[sourceWalkFunc] err:",err) } return nil } } func parseFile(currfile string,done func()) { if done != nil { defer done() } //这地方要注意,配置要对。 destFile := strings.Replace(currfile,repConf.SourceDir,repConf.DestDir,-1) if destFile == currfile { panic("[parseFile] ERROR 没有替换对. SourceDir与DestDir配置出问题了。请检查Json配置.") } destDir := filepath.Dir(destFile) if _,er := os.Stat(destDir); os.IsNotExist(er) { if err := os.MkdirAll(destDir,0700); err != nil { fmt.Println("[parseFile] MkdirAll ",destDir) panic(err) } } fmt.Println("[parseFile] 源文件:",currfile) fmt.Println("[parseFile] 目标文件:",destFile) ///////////////////////////////////////////////// oldFile,err := os.Open(currfile) if err != nil { fmt.Println("[parseFile] Failed to open the input file ",oldFile) return } defer oldFile.Close() newFile,err := os.Create(destFile) if err != nil { panic(err) } defer newFile.Close() f1 := func(ext string) bool { for _,e := range repConf.FileExtension { if ext == e { return true } } return false } if f1(filepath.Ext(currfile)) { copyRepFile(newFile,oldFile) extFileNum++ } else { if _,err := io.Copy(newFile,oldFile); err != nil { panic(err) } otherFileNum++ } } func copyRepFile(newFile,oldFile *os.File) { br := bufio.NewReader(oldFile) bw := bufio.NewWriter(newFile) for { row,err1 := br.ReadString(byte('\n')) if err1 != nil { break } str := string(row) if str == "" { continue } ret := repReplacer.Replace(str) //fmt.Println("[copyRepFile] str:",str) //fmt.Println("[copyRepFile] ret:",ret) if _,err := bw.WriteString(ret); err != nil { panic(err) } } bw.Flush() } func parseJsonFile() { f,err := os.Open(flagFile) if err != nil { panic("[parseJsonFile] open Failed!") } defer f.Close() j,err := IoUtil.ReadAll(f) if err != nil { panic("[parseJsonFile] ReadAll Failed!") } err = json.Unmarshal(j,&repConf) if err != nil { fmt.Println("[parseJsonFile] json err:",err) panic("[parseJsonFile] Unmarshal Failed!") } fmt.Println(" ------------------------------------------------------") fmt.Println(" 源目录:",repConf.SourceDir) fmt.Println(" 目标目录:",repConf.DestDir) fmt.Println(" 仅包含的指定扩展名的文件:",repConf.FileExtension) for _,e := range repConf.FileExtension { fmt.Println(" 文件扩展名:",e) } arr := make([]string,1) for _,v := range repConf.ReplaceWhere { fmt.Println(" 原文本:",v.FindWhat," 替换为:",v.ReplaceWith) arr = append(arr,v.FindWhat) arr = append(arr,v.ReplaceWith) } repReplacer = strings.NewReplacer(arr...) fmt.Println(" ------------------------------------------------------") if repConf.SourceDir == "" || repConf.DestDir == "" { panic("[parseJsonFile] 目录设置不对!") } }
贴一个Windows下的例子:
Windows配置例子: { "sourcedir":"E:\\xclgo\\src\\test\\aaa\\","destdir":"E:\\xclgo\\src\\test\\bbb\\","replacewhere":[{ "findwhat":"parseFile","replacewith":"----parseFile----" },"replacewith":"192.168.1.101" }] } 运行结果: E:\xclgo\src\test>go run batchreplace.go ------------------------------------------------------ 源目录: E:\xclgo\src\test\aaa\ 目标目录: E:\xclgo\src\test\bbb\ 仅包含的指定扩展名的文件: [.go .conf] 文件扩展名: .go 文件扩展名: .conf 原文本: parseFile 替换为: ----parseFile---- 原文本: 172.18.1.101 替换为: 192.168.1.101 ------------------------------------------------------ dirname: E:\xclgo\src\test\aaa\ [sourceWalkFunc] err: <nil> [parseFile] 源文件: E:\xclgo\src\test\aaa\testfile.go [parseFile] 目标文件: E:\xclgo\src\test\bbb\testfile.go elapsed 0.004000 seconds 处理统计 处理指定类型文件: 1 处理其它文件: 0
就不演示包含子目录的了。 其中参数就是把Json内容存到“flag.json”文件里,运行时会自动去读取配置。