面试题答案
一键面试package main
import (
"bufio"
"encoding/json"
"fmt"
"io"
"os"
)
// 定义JSON记录的结构体,假设日志记录包含 "fieldToAnalyze" 字段
type LogRecord struct {
FieldToAnalyze string `json:"fieldToAnalyze"`
// 其他字段可以根据实际日志结构添加
}
func processLogFile(inputFilePath, outputFilePath string) error {
inputFile, err := os.Open(inputFilePath)
if err != nil {
return err
}
defer inputFile.Close()
outputFile, err := os.Create(outputFilePath)
if err != nil {
return err
}
defer outputFile.Close()
scanner := bufio.NewScanner(inputFile)
resultMap := make(map[string]int)
var wg sync.WaitGroup
// 使用通道来控制并发读取
linesChan := make(chan string, 1000)
go func() {
for scanner.Scan() {
linesChan <- scanner.Text()
}
close(linesChan)
}()
// 启动多个goroutine进行处理
numWorkers := 5
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for line := range linesChan {
var record LogRecord
err := json.Unmarshal([]byte(line), &record)
if err != nil {
fmt.Printf("解析JSON错误: %v\n", err)
continue
}
resultMap[record.FieldToAnalyze]++
}
}()
}
go func() {
wg.Wait()
close(resultChan)
}()
// 将结果写入新文件
for result := range resultChan {
_, err := outputFile.WriteString(fmt.Sprintf("%s: %d\n", result.key, result.value))
if err != nil {
return err
}
}
return nil
}
你可以使用以下方式调用这个函数:
func main() {
inputFilePath := "input.log"
outputFilePath := "output.txt"
err := processLogFile(inputFilePath, outputFilePath)
if err != nil {
fmt.Printf("处理日志文件出错: %v\n", err)
}
}
代码说明:
- 结构体定义:定义
LogRecord
结构体来匹配JSON记录的结构,这里只包含需要分析的字段,实际应用中可根据日志结构添加其他字段。 - 文件读取:使用
os.Open
打开输入日志文件,使用bufio.NewScanner
逐行读取文件内容,利用通道linesChan
进行缓冲,以便多个goroutine并发处理。 - JSON解析与统计:启动多个goroutine从通道中读取日志行,使用
json.Unmarshal
解析JSON并对特定字段进行统计,统计结果存放在resultMap
中。 - 结果写入:将统计结果写入到新的文件中,使用
os.Create
创建输出文件,通过outputFile.WriteString
写入每一条统计结果。 - 资源管理:使用
defer
语句确保文件在函数结束时正确关闭,以释放资源。使用sync.WaitGroup
等待所有goroutine完成任务后再关闭通道和写入结果。