Golang-常用第三方库 - Go语言中文社区

Golang-常用第三方库


goleak——Goroutine 泄漏防治神器

【酷Go推荐】Goroutine 泄漏防治神器 goleak

Golang 命令行工具——urfave/cli

用法

Flag

  • c.String(“startDate”):获取startDate这个flag

参考文档

Go语言命令行库urfave/cli简介
Golang的一个CLI框架介绍,个人学习备忘
cli - 构建强大命令行程序的工具箱 (1)

Golang处理Excel

Excelize

微服务

Go语言构建微服务一站式解决方案
Go微服务 - 第一部分 - 介绍及理论基础
Go 微服务实战汇总
Go实践微服务 – go-micro编写微服务
哔哩哔哩-哔哩哔哩的Go微服务实战
04【千锋Go语言】Go语言微服务实践
go-micro电商项目实战简介

请求路由-mux

mux学习
Golang 第三方库学习 · mux
golang进阶(四)——路由mux的最佳实践
Gorilla学习笔记

日志-logrus

golang日志框架logrus
logrus 安装 使用
logrus日志使用详解
golang日志框架之logrus

参数校验-validator

6.4. validator 请求校验
Golang validator 详解

定时任务-robfig/cron

golang cron 定时任务使用
Gin实践 连载十一 Cron定时任务
github.com/robfig/cron【Golang 常用包推荐】
golang版的crontab
golang crontab的计划任务及定时任务使用
golang cron定时任务
Go cron定时任务的用法

统计代码行数

相关问题

defer func() 和 defer “代码段” 哪个先执行?

需加强学习的知识点

  • go并发(mutex)相关知识点
  • go命令行参数相关知识点
  • go文件相关知识点

参考代码

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
	"sync"
)

var (
	linesum int									// 总代码行数, 全局变量, 需控制并发修改
	mutex   *sync.Mutex = new(sync.Mutex)		// 互斥锁
)

var (
	rootPath string = "/home/cx4gxf/GoEnv/src/go-test"		// 要进行代码统计的根路径
	// 被排除(不进行代码统计)的子路径
	nodirs [6]string = [...]string{"/vendor/golang.org", "/bitbucket.org", "/vendor/github.com", "/goplayer", "/uniqush", "/code.google.com"}
	suffixname 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]
	}

	done := make(chan bool)						// done channel用于控制main goroutine的结束时机
	go codeLineSum(rootPath, done)
	<-done

	fmt.Println("total line------------------------------------------------------------------------------", linesum)
}

func codeLineSum(root string, done chan bool) {
	var goes int              // 子goroutine的数目,对每一个文件单独开一个goroutine进行代码行数统计
	
	godone := make(chan bool) // godone channel用于控制codeLineSum goroutine的结束时机

	// 校验当前目录是否为要进行代码统计的子目录
	isDstDir := checkDir(root)

	defer func() {
		if pan := recover(); pan != nil {
			fmt.Printf("root: %s, panic:%#vn", root, pan)
		}

		// waiting for his children done
		for i := 0; i < goes; i++ {
			<- godone
		}

		// this goroutine done, notify his parent
		done <- true
	}()

	if !isDstDir {
		return
	}

	// 获取根文件信息
	rootfi, err := os.Lstat(root)
	checkerr(err)

	// 打开根路径
	rootdir, err := os.Open(root)
	checkerr(err)
	defer rootdir.Close()

	if rootfi.IsDir() {
		// 获取目录剩余的FileInfo构成的Slice
		fis, err := rootdir.Readdir(0)
		checkerr(err)

		for _, fi := range fis {
			// 跳过目录中的隐藏文件和文件夹 .fileName--在linux中表示隐藏文件或文件夹
			if strings.HasPrefix(fi.Name(), ".") {
				continue
			}

			// 对每一个文件, 开启一个goroutine进行代码行数统计
			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 child
		go readfile(root, godone)
	}
}

// 统计单个文件的代码行数
//		filename string: 文件名, 绝对路径
//		done chan bool: 控制main goroutine结束的channel, 每个统计单个文件代码行数的goroutine结束时, 会向该channel写入true, 表示当前goroutine的结束
func readfile(filename string, done chan bool) {
	var line int	// 当前文件的代码行数

	// 根据文件后缀名判定当前文件是否为要进行代码行数统计的目标文件
	isDstFile := strings.HasSuffix(filename, suffixname)

	defer func() {
		// 异常处理
		if pan := recover(); pan != nil {
			fmt.Printf("filename: %s, panic:%#vn", filename, pan)
		}

		// 如果当前文件是目标文件,则修改全局变量linesum
		if isDstFile {
			addLineNum(line)
			fmt.Printf("file %s complete, line = %dn", filename, line)
		}

		// 当前goroutine结束, 向done channel写入true, 通知父goroutine当前goroutine的结束
		// this goroutine done, notify his parent
		done <- true
	}()

	// 如果当前文件不是要进行代码行数统计的文件, 则直接退出, 在函数退出前执行defer相关代码
	if !isDstFile {
		return
	}

	// 打开当前文件,用于后续读取,在退出前关闭文件
	file, err := os.Open(filename)
	checkerr(err)
	defer file.Close()

	// 循环读取文件中的每一行,isPrefix表示在返回数据时是否对该行进行了切割
	reader := bufio.NewReader(file)
	for {
		_, isPrefix, err := reader.ReadLine()
		if err != nil {
			break
		}

		// 未对该行进行切割, 则line自增
		if !isPrefix {
			line++
		}
	}
}

// 校验当前目录是否为要进行代码统计的目录
// check whether this dir is the dest dir
func checkDir(dirpath string) bool {
	for _, dir := range nodirs {
		if rootPath + dir == dirpath {
			return false
		}
	}
	return true
}

func addLineNum(num int) {
	mutex.Lock()
	defer mutex.Unlock()

	linesum += num
}

// if error happened, throw a panic, and the panic will be recover in defer function
func checkerr(err error) {
	if err != nil {
		panic(err.Error())
	}
}

测试&使用

使用说明

go run count_line.go rootPath suffixName
	- rootPath: 可选参数,要进行代码统计的项目根路径
	- suffixName: 可选参数,要进行代码统计的文件后缀

使用示例

直接运行项目,统计默认的项目根路径的代码行数

其中,默认的项目根路径/默认被排除的路径/默认的文件后缀 可在代码中执行配置

var (
	// the dir where souce file stored
	rootPath string = "/home/cx4gxf/GoEnv/src/go-test"
	// exclude these sub dirs								项目中被排除(不进行代码)的子路径
	nodirs [6]string = [...]string{"/vendor/golang.org", "/bitbucket.org", "/vendor/github.com", "/goplayer", "/uniqush", "/code.google.com"}
	// the suffix name you care
	suffixname string = ".go"
)

在这里插入图片描述

运行项目,指定要进行代码统计的项目的根路径

在这里插入图片描述

运行项目,指定要进行代码统计的项目的根路径及文件后缀

在这里插入图片描述

参考文档

用golang代码统计整个工程的代码行数

识别和生成二维码

用GO生成和识别二维码

实现状态机

Go语言实现有限状态机(FSM)

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/CSDN_FlyYoung/article/details/101484639
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-05-13 22:18:10
  • 阅读 ( 2230 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢