使用golang统计代码行数

编程技术  /  houtizong 发布于 3年前   224

有关golang的介绍请参考我的另一篇博文.

 

 

本文通过递归遍历src目录, 统计代码行数. 涉及到的知识点有:

1. 目录遍历.

2. 读取文件.

3. 使用channel进行goroutine间的通信.

4. 使用sync包进行传统的共享内存方式的同步.

5. 错误处理.

6. defer语句的使用.

 

 

在程序中有详细的注释:

 

// a simple go program for computing total line of souce files stored in one dirpackage mainimport ("fmt""bufio""os""sync""strings")var (linesum intmutex   *sync.Mutex = new(sync.Mutex))var (// the dir where souce file storedrootPath string = "/home/xing/Dropbox/source/go/src"// exclude these sub dirsnodirs [5]string = [...]string{"/bitbucket.org", "/github.com", "/goplayer", "/uniqush", "/code.google.com"}// the suffix name you caresuffixname string = ".go")func main() {argsLen := len(os.Args)if argsLen == 2 {rootPath = os.Args[1]} else if argsLen == 3 {rootPath = os.Args[1]suffixname = os.Args[2]}// sync chan using for waitingdone := make(chan bool)go codeLineSum(rootPath, done)<-donefmt.Println("total line:", linesum)}// compute souce file line numberfunc codeLineSum(root string, done chan bool) {var goes int              // children goroutines numbergodone := make(chan bool) // sync chan using for waiting all his children goroutines finishedisDstDir := checkDir(root)defer func() {if pan := recover(); pan != nil {fmt.Printf("root: %s, panic:%#v\n", root, pan)}// waiting for his children donefor i := 0; i < goes; i++ {<-godone}// this goroutine done, notify his parentdone <- true}()if !isDstDir {return}rootfi, err := os.Lstat(root)checkerr(err)rootdir, err := os.Open(root)checkerr(err)defer rootdir.Close()if rootfi.IsDir() {fis, err := rootdir.Readdir(0)checkerr(err)for _, fi := range fis {if strings.HasPrefix(fi.Name(), ".") {continue}goes++if fi.IsDir() {go codeLineSum(root+"/"+fi.Name(), godone)} else {go readfile(root+"/"+fi.Name(), godone)}}} else {goes = 1 // if rootfi is a file, current goroutine has only one childgo readfile(root, godone)}}func readfile(filename string, done chan bool) {var line intisDstFile := strings.HasSuffix(filename, suffixname)defer func() {if pan := recover(); pan != nil {fmt.Printf("filename: %s, panic:%#v\n", filename, pan)}if isDstFile {addLineNum(line)fmt.Printf("file %s complete, line = %d\n", filename, line)}// this goroutine done, notify his parentdone <- true}()if !isDstFile {return}file, err := os.Open(filename)checkerr(err)defer file.Close()reader := bufio.NewReader(file)for {_, isPrefix, err := reader.ReadLine()if err != nil {break}if !isPrefix {line++}}}// check whether this dir is the dest dirfunc checkDir(dirpath string) bool {// 判断该文件夹是否在被排除的范围之内for _, dir := range nodirs {if rootPath+dir == dirpath {return false}}return true}func addLineNum(num int) {// 获取锁mutex.Lock()// defer语句在函数返回时调用, 确保锁被释放defer mutex.Unlock()linesum += num}// if error happened, throw a panic, and the panic will be recover in defer functionfunc checkerr(err error) {if err != nil {// 在发生错误时调用panic, 程序将立即停止正常执行, 开始沿调用栈往上抛, 直到遇到recover// 对于java程序员, 可以将panic类比为exception, 而recover则是try...catchpanic(err.Error())}}
 

 

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

留言需要登陆哦

技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成

网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];

      订阅博客周刊 去订阅

文章归档

文章标签

友情链接

Auther ·HouTiZong
侯体宗的博客
© 2020 zongscan.com
版权所有ICP证 : 粤ICP备20027696号
PHP交流群 也可以扫右边的二维码
侯体宗的博客