MST

星途 面试题库

面试题:Go标准库在复杂文件操作中的应用

假设你需要处理一个非常大的日志文件(可能超过内存容量),文件格式为每行一个JSON记录。请使用Go标准库设计一个高效的方案,能够逐行读取并解析JSON记录,对特定字段进行统计分析,并将结果写入到新文件中,同时要考虑高并发处理以及资源的合理释放。
30.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
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)
    }
}

代码说明:

  1. 结构体定义:定义 LogRecord 结构体来匹配JSON记录的结构,这里只包含需要分析的字段,实际应用中可根据日志结构添加其他字段。
  2. 文件读取:使用 os.Open 打开输入日志文件,使用 bufio.NewScanner 逐行读取文件内容,利用通道 linesChan 进行缓冲,以便多个goroutine并发处理。
  3. JSON解析与统计:启动多个goroutine从通道中读取日志行,使用 json.Unmarshal 解析JSON并对特定字段进行统计,统计结果存放在 resultMap 中。
  4. 结果写入:将统计结果写入到新的文件中,使用 os.Create 创建输出文件,通过 outputFile.WriteString 写入每一条统计结果。
  5. 资源管理:使用 defer 语句确保文件在函数结束时正确关闭,以释放资源。使用 sync.WaitGroup 等待所有goroutine完成任务后再关闭通道和写入结果。