您的位置:首页 > 编程语言 > Go语言

批量替换和转移目录的东东

2015-10-24 01:34 666 查看
     拷,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, 0, 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\\",
"fileext":[".go",".conf"],
"replacewhere":[{
"findwhat":"parseFile",
"replacewith":"----parseFile----"
},
{
"findwhat":"172.18.1.101",
"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”文件里,运行时会自动去读取配置。

 

BLOG: http://blog.csdn.net/xcl168
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  golang go 批量替换