Golang CSV文件解析与处理指南

Golang CSV文件解析与处理指南 我有一份以CSV格式导出的绩效报告,想将其导入到我的Web应用中。数据以如下格式呈现:

员工每日绩效
桥街
Abbi Clarke
日期
02/01/2019
03/01/2019
04/01/2019
Adam Carter
日期
02/01/2019
03/01/2019
04/01/2019
James Sharpe
日期
02/01/2019
03/01/2019
04/01/2019

我希望将每个团队成员的数据分离到一个映射切片 []map[string][]string 中,以团队成员姓名作为键,数字作为字符串切片——忽略所有其他内容。

这样我就可以使用 encoding/csv 包遍历每个映射,以便将其上传到我的数据库。

我应该如何以这种方式读取文档?


更多关于Golang CSV文件解析与处理指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

一些问题:

  • 如何识别团队成员的姓名?
  • 如何识别团队成员的“数据”?
  • 根据你问题中的数据,预期的 []map[string][]string 结果应该是什么?
  • 你已经尝试过哪些方法?
  • 它有效吗?
  • 如果无效,具体哪里有问题?

更多关于Golang CSV文件解析与处理指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


  • 每个团队成员对应一个人名。
  • 后续的数据(以日期开头的行)是具体数值。
  • 我希望将每个团队成员的数据子集存储到映射(map)中,并以团队成员的名字作为键。
  • 我目前的解决方法是手动将数据分割成单独的CSV文件,每个文件对应一个团队成员的数据——我使用团队成员的名字作为文件名。然后,我使用encoding/csv包来读取每个文件。

我对Go语言(以及编程本身)还比较陌生——我已经在论坛上仔细搜索过,试图找到解决方案,但仍然没有成功!任何帮助都将不胜感激。

package main

import (
    "encoding/csv"
    "fmt"
    "io"
    "os"
    "strings"
)

func parseCSV(filePath string) ([]map[string][]string, error) {
    file, err := os.Open(filePath)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    reader := csv.NewReader(file)
    var result []map[string][]string
    var currentEmployee string
    var employeeData []string
    inDataSection := false
    headerCount := 0

    for {
        record, err := reader.Read()
        if err == io.EOF {
            break
        }
        if err != nil {
            return nil, err
        }

        if len(record) == 0 {
            continue
        }

        firstField := strings.TrimSpace(record[0])
        
        if firstField == "员工每日绩效" || firstField == "桥街" {
            continue
        }

        if strings.Contains(firstField, "/") {
            if inDataSection && currentEmployee != "" {
                employeeData = append(employeeData, strings.Join(record, ","))
            }
            continue
        }

        if isName(firstField) {
            if currentEmployee != "" && len(employeeData) > 0 {
                result = append(result, map[string][]string{
                    currentEmployee: employeeData,
                })
            }
            currentEmployee = firstField
            employeeData = []string{}
            inDataSection = false
            headerCount = 0
            continue
        }

        if firstField == "日期" {
            headerCount++
            if headerCount == 2 {
                inDataSection = true
            }
            continue
        }
    }

    if currentEmployee != "" && len(employeeData) > 0 {
        result = append(result, map[string][]string{
            currentEmployee: employeeData,
        })
    }

    return result, nil
}

func isName(field string) bool {
    names := []string{"Abbi Clarke", "Adam Carter", "James Sharpe"}
    for _, name := range names {
        if field == name {
            return true
        }
    }
    return false
}

func main() {
    data, err := parseCSV("performance.csv")
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    for _, empMap := range data {
        for name, records := range empMap {
            fmt.Printf("Employee: %s\n", name)
            for _, record := range records {
                fmt.Printf("  Data: %s\n", record)
            }
        }
    }
}
// 更健壮的版本,包含数据验证
package main

import (
    "encoding/csv"
    "fmt"
    "io"
    "os"
    "strings"
)

type EmployeeData struct {
    Name   string
    Records []string
}

func parseCSVAdvanced(filePath string) ([]map[string][]string, error) {
    file, err := os.Open(filePath)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    reader := csv.NewReader(file)
    reader.FieldsPerRecord = -1
    
    var result []map[string][]string
    var currentEmployee string
    var recordsBuffer []string
    dataMode := false
    skipNext := false

    for lineNum := 1; ; lineNum++ {
        record, err := reader.Read()
        if err == io.EOF {
            break
        }
        if err != nil {
            continue
        }

        if len(record) == 0 {
            continue
        }

        firstCell := strings.TrimSpace(record[0])
        
        switch {
        case firstCell == "":
            continue
            
        case strings.Contains(firstCell, "员工每日绩效"):
            continue
            
        case strings.Contains(firstCell, "桥街"):
            continue
            
        case isEmployeeName(firstCell):
            if currentEmployee != "" && len(recordsBuffer) > 0 {
                result = append(result, map[string][]string{
                    currentEmployee: cleanRecords(recordsBuffer),
                })
            }
            currentEmployee = firstCell
            recordsBuffer = []string{}
            dataMode = false
            skipNext = false
            
        case firstCell == "日期" && !skipNext:
            skipNext = true
            continue
            
        case firstCell == "日期" && skipNext:
            dataMode = true
            skipNext = false
            continue
            
        case dataMode && isDate(firstCell):
            recordsBuffer = append(recordsBuffer, strings.Join(record, ","))
            
        default:
            continue
        }
    }

    if currentEmployee != "" && len(recordsBuffer) > 0 {
        result = append(result, map[string][]string{
            currentEmployee: cleanRecords(recordsBuffer),
        })
    }

    return result, nil
}

func isEmployeeName(str string) bool {
    knownNames := map[string]bool{
        "Abbi Clarke":  true,
        "Adam Carter":  true,
        "James Sharpe": true,
    }
    return knownNames[str]
}

func isDate(str string) bool {
    return strings.Contains(str, "/") && len(str) == 10
}

func cleanRecords(records []string) []string {
    var cleaned []string
    for _, r := range records {
        trimmed := strings.TrimSpace(r)
        if trimmed != "" {
            cleaned = append(cleaned, trimmed)
        }
    }
    return cleaned
}

func main() {
    data, err := parseCSVAdvanced("performance.csv")
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    for i, empMap := range data {
        fmt.Printf("Record %d:\n", i+1)
        for name, records := range empMap {
            fmt.Printf("  Employee: %s\n", name)
            fmt.Printf("  Record count: %d\n", len(records))
            for j, record := range records {
                fmt.Printf("    [%d] %s\n", j+1, record)
            }
        }
    }
}
// 数据库上传示例
package main

import (
    "database/sql"
    "encoding/csv"
    "fmt"
    "strings"
    _ "github.com/lib/pq"
)

func uploadToDB(data []map[string][]string, db *sql.DB) error {
    for _, empMap := range data {
        for empName, records := range empMap {
            for _, record := range records {
                fields := strings.Split(record, ",")
                if len(fields) >= 9 {
                    _, err := db.Exec(`
                        INSERT INTO performance 
                        (employee_name, date, service_excl, service_total, 
                         course_excl, course_total, product_excl, product_total, 
                         hours, minutes) 
                        VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,
                        empName,
                        fields[0],
                        fields[1],
                        fields[2],
                        fields[3],
                        fields[4],
                        fields[5],
                        fields[6],
                        fields[7],
                        fields[8],
                    )
                    if err != nil {
                        return err
                    }
                }
            }
        }
    }
    return nil
}
回到顶部