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