在日常的数据处理、日志分析、数据导入场景中,CSV(Comma-Separated Values)作为一种简单而强大的数据格式,被广泛使用。本文将介绍如何使用 Golang 高效地读取 CSV 文件、查询数据,并导入到 MySQL 数据库中。

场景背景

我们有一个包含数百万行、约 600MB 的 CSV 文件,结构如下:

network,country,country_code,continent,continent_code,asn,as_name,as_domain
1.0.0.0/24,Australia,AU,Oceania,OC,13335,Cloudflare Inc.,cloudflare.com
...

目标:

  • 使用 Go 解析此 CSV 文件
  • 将数据插入到 MySQL 表中(ipinfos
  • 支持处理空值、类型转换等情况

1. 使用 Go 读取 CSV 文件

Go 标准库中的 encoding/csv 包提供了便捷的解析方式。下面是一个基础示例,用于读取 CSV 并生成对应的 SQL 插入语句:

package main

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

func main() {
    f, err := os.Open("info_lite.csv")
    if err != nil {
        panic(err)
    }
    defer f.Close()

    reader := csv.NewReader(f)
    headers, err := reader.Read()
    if err != nil {
        panic(err)
    }

    tableName := "ipinfos"
    for {
        record, err := reader.Read()
        if err != nil {
            break
        }

        values := make([]string, len(record))
        for i, val := range record {
            val = strings.ReplaceAll(val, "'", "''") // 防止 SQL 注入
            if val == "" {
                values[i] = "NULL"
            } else {
                values[i] = fmt.Sprintf("'%s'", val)
            }
        }

        fmt.Printf("INSERT INTO %s (%s) VALUES (%s);\n",
            tableName,
            strings.Join(headers, ", "),
            strings.Join(values, ", "),
        )
    }
}

执行后可将结果重定向输出为 SQL 文件:

$ go run main.go > ipinfos_data.sql

2. MySQL 建表语句

为配合导入,需先创建表结构:

CREATE TABLE ipinfos (
    network VARCHAR(50),
    country VARCHAR(100),
    country_code VARCHAR(10),
    continent VARCHAR(50),
    continent_code VARCHAR(10),
    asn VARCHAR(64),
    as_name VARCHAR(255),
    as_domain VARCHAR(255)
);

3. 执行 SQL 脚本导入 MySQL

执行导出的 SQL 文件:

$ mysql -u root -p your_database < ipinfos_data.sql

或使用 LOAD DATA INFILE 更高效地导入原始 CSV:

LOAD DATA LOCAL INFILE '/path/to/ipinfo_lite.csv'
INTO TABLE ipinfos
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(network, country, country_code, continent, continent_code, asn, as_name, as_domain);

确保开启 local_infile 支持:

$ mysql --local-infile=1 -u root -p

孟斯特

声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin
blog: mengbin
Github: mengbin92
腾讯云开发者社区:孟斯特