首页 > 其他分享 >一段多协程处理的日志文件代码

一段多协程处理的日志文件代码

时间:2023-03-19 15:33:49浏览次数:35  
标签:string nil battery 代码 多协程 Value int64 日志 uTime

package main

import (
	"bufio"
	"encoding/csv"
	"flag"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strings"
	"sync"
	"time"
)

type BatteryPercent struct {
	Timestamp int64
	Value     float64
}

type BatteryTemp struct {
	Timestamp int64
	Value     float64
}

type BatteryVoltage struct {
	Timestamp int64
	Value     float64
}

type Current struct {
	Timestamp int64
	Value     float64
}

type TimeValue struct {
	TimestampMilli int64
	Value          string
}

var m map[int64]*map[string]*TimeValue
var timestampArr []int64

var RWlock *sync.RWMutex

func init() {
	RWlock = new(sync.RWMutex)
	m = make(map[int64]*map[string]*TimeValue)
}

func main() {
	var logFilename string
	var emptyValue string
	flag.StringVar(&logFilename, "file", "", "需要处理的文件名")
	// except:排除,zero:0值,empty:空字符串
	flag.StringVar(&emptyValue, "emptyValue", "except", "空值处理方式")
	// 必须有这一行
	flag.Parse()
	c := make(chan string, 1024)
	go readFile(logFilename, c)
	fmt.Println("骚等一下,正在处理中...")
	// 开多个协程读取文件
	var wg sync.WaitGroup
	count := 5
	for i := 0; i < count; i++ {
		go executeLog(c, &wg)
		wg.Add(1)
	}
	wg.Wait()
	// 写入csv文件
	filename := time.Now().Format("2006-02-01_15_04_05") + ".csv"
	file, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR, 0644)
	defer file.Close()
	if err != nil {
		fmt.Println("读取文件错误: ", err)
	}
	// 写入UTF-8 BOM,防止中文乱码
	file.WriteString("\xEF\xBB\xBF")
	w := csv.NewWriter(file)
	writeArr := []string{"时间", "电量", "温度", "电流", "电压"}
	w.Write(writeArr)
	sort.Slice(timestampArr, func(i, j int) bool { return timestampArr[i] < timestampArr[j] })
	for _, t := range timestampArr {
		if m[t] == nil {
			continue
		}
		p := *m[t]
		batteryPercent := ""
		batteryTemp := ""
		batteryVoltage := ""
		current := ""
		uTime := t * 1000
		if p["battery_temp"] != nil {
			batteryTemp = p["battery_temp"].Value
			uTime = p["battery_temp"].TimestampMilli
		}
		if p["battery_percent"] != nil {
			batteryPercent = p["battery_percent"].Value
			uTime = p["battery_percent"].TimestampMilli
		}
		if p["battery_voltage"] != nil {
			batteryVoltage = p["battery_voltage"].Value
			uTime = p["battery_voltage"].TimestampMilli
		}
		if p["Current"] != nil {
			current = p["Current"].Value
			uTime = p["Current"].TimestampMilli
		}
		// except:排除,zero:0值,empty:空字符串
		if emptyValue == "except" {
			if batteryPercent == "" || batteryTemp == "" || current == "" || batteryVoltage == "" {
				continue
			}
		}
		if emptyValue == "zero" {
			if batteryPercent == "" {
				batteryPercent = "0"
			}
			if batteryTemp == "" {
				batteryTemp = "0"
			}
			if current == "" {
				current = "0"
			}
			if batteryVoltage == "" {
				batteryVoltage = "0"
			}
		}

		//format := "2006-02-01_15:04:05.000"
		format := "15:04:05.000"
		uTimeStr := time.UnixMilli(uTime).Format(format)
		writeArr := []string{uTimeStr, batteryPercent, batteryTemp, current, batteryVoltage}
		w.Write(writeArr)
		// 写文件需要flush,不然缓存满了,后面的就写不进去了,只会写一部分
		w.Flush()
	}
	fmt.Println("处理完毕,CSV文件:" + filename)

}

func readFile(fileName string, c chan string) {
	readFile, err := os.Open(fileName)
	defer readFile.Close()
	// 写完数据再close channel
	defer close(c)
	if err != nil {
		fmt.Println(err)
	}
	fileScanner := bufio.NewScanner(readFile)
	fileScanner.Split(bufio.ScanLines)
	for fileScanner.Scan() {
		l := fileScanner.Text()
		c <- l
	}
}

func executeLog(c chan string, w *sync.WaitGroup) {
	for {
		l, ok := <-c
		if !ok {
			w.Done()
			return
		}
		getValue(l)
	}
}

// 正则匹配值
func getValue(str string) {
	pregArr := []string{
		`\[([\d]{4}-[\d]{2}-[\d]{2}\s[\d]{2}:[\d]{2}:[\d]{2}\.[\d]{3})\].*?(battery_temp)[\s]*:[\s]*([\d]+.?[\d]*)`,
		`\[([\d]{4}-[\d]{2}-[\d]{2}\s[\d]{2}:[\d]{2}:[\d]{2}\.[\d]{3})\].*?(battery_percent)[\s]*:[\s]*([\d]+.?[\d]*)`,
		`\[([\d]{4}-[\d]{2}-[\d]{2}\s[\d]{2}:[\d]{2}:[\d]{2}\.[\d]{3})\].*?(Current)[\s]*\=[\s]*([\d]+.?[\d]*)`,
		`\[([\d]{4}-[\d]{2}-[\d]{2}\s[\d]{2}:[\d]{2}:[\d]{2}\.[\d]{3})\].*?(battery_voltage)[\s]*:[\s]*([\d]+.?[\d]*)`,
	}
	for _, r := range pregArr {
		re := regexp.MustCompile(r)
		matched := re.FindAllStringSubmatch(str, -1)
		for _, match := range matched {
			format := "2006-02-01 15:04:05.000"
			t, err := time.Parse(format, match[1])
			if err != nil {
				fmt.Println("错误的时间", match[1])
				continue
			}
			timestamp := t.Unix()
			timestampMilli := t.UnixMilli()
			// 对应秒
			RWlock.Lock()
			p := m[timestamp]
			param := match[2]
			value := strings.Trim(match[3], ".")
			// 指定时间戳无数据则设置
			if p == nil {
				m[timestamp] = &map[string]*TimeValue{
					param: &TimeValue{
						TimestampMilli: timestampMilli,
						Value:          value,
					},
				}
				timestampArr = append(timestampArr, timestamp)
			} else {
				// 不为空则表示对应的秒有值,则判断
				v := *m[timestamp]
				// nil 表示没有设置过
				if v[param] == nil {
					v[param] = &TimeValue{
						TimestampMilli: timestampMilli,
						Value:          value,
					}
					// 设置过则比较时间大小,取时间大的对应的值
				} else if v[param].TimestampMilli < t.UnixMilli() {
					v[param] = &TimeValue{
						TimestampMilli: timestampMilli,
						Value:          value,
					}
				}
			}
			RWlock.Unlock()
		}
	}

}

标签:string,nil,battery,代码,多协程,Value,int64,日志,uTime
From: https://www.cnblogs.com/jing1024/p/17233342.html

相关文章