Golang CSV工具 - diffcsv的发布与使用
Golang CSV工具 - diffcsv的发布与使用 添加了一个用于比较两个CSV文件的差异工具。由于需要将两个输入文件都保留在内存中进行比较,该工具受限于内存大小。更多详情请参阅此处。
目前命令行工具列表如下:
catcsv
comparecsv
dedupcsv
diffcsv
editcsv
obfuscatecsv
pivotcsv
recursedata
reordercsv
searchcsv
sortcsv
splitcsv
1 回复
更多关于Golang CSV工具 - diffcsv的发布与使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这是一个很有用的工具发布!diffcsv 作为 csv-utils 工具集的一部分,为 CSV 文件比较提供了专门解决方案。以下是对该工具的技术分析和使用示例:
技术实现分析
diffcsv 的核心逻辑是通过将两个 CSV 文件完全加载到内存中进行行级比较。这种设计确保了比较的准确性,但也确实带来了内存限制的挑战。
典型的实现架构如下:
package main
import (
"encoding/csv"
"fmt"
"io"
"os"
)
type CSVDiff struct {
Added [][]string
Removed [][]string
Changed [][]string
}
func CompareCSVFiles(file1, file2 string) (*CSVDiff, error) {
// 读取第一个CSV文件到内存
records1, err := readCSV(file1)
if err != nil {
return nil, err
}
// 读取第二个CSV文件到内存
records2, err := readCSV(file2)
if err != nil {
return nil, err
}
diff := &CSVDiff{}
// 构建记录映射以便快速查找
map1 := make(map[string]bool)
for _, record := range records1 {
key := generateKey(record)
map1[key] = true
}
map2 := make(map[string]bool)
for _, record := range records2 {
key := generateKey(record)
map2[key] = true
// 检查是否为新添加的记录
if !map1[key] {
diff.Added = append(diff.Added, record)
}
}
// 检查被删除的记录
for _, record := range records1 {
key := generateKey(record)
if !map2[key] {
diff.Removed = append(diff.Removed, record)
}
}
return diff, nil
}
func readCSV(filename string) ([][]string, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
reader := csv.NewReader(file)
var records [][]string
for {
record, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
records = append(records, record)
}
return records, nil
}
func generateKey(record []string) string {
// 简单的键生成逻辑,实际实现可能更复杂
key := ""
for _, field := range record {
key += field + "|"
}
return key
}
使用示例
func main() {
diff, err := CompareCSVFiles("file1.csv", "file2.csv")
if err != nil {
fmt.Printf("比较失败: %v\n", err)
return
}
fmt.Printf("新增记录数: %d\n", len(diff.Added))
fmt.Printf("删除记录数: %d\n", len(diff.Removed))
// 输出具体差异
if len(diff.Added) > 0 {
fmt.Println("新增的记录:")
for _, record := range diff.Added {
fmt.Println(record)
}
}
if len(diff.Removed) > 0 {
fmt.Println("删除的记录:")
for _, record := range diff.Removed {
fmt.Println(record)
}
}
}
内存优化考虑
对于大文件场景,可以考虑流式处理方案:
func StreamCompareCSVFiles(file1, file2 string) error {
f1, err := os.Open(file1)
if err != nil {
return err
}
defer f1.Close()
f2, err := os.Open(file2)
if err != nil {
return err
}
defer f2.Close()
reader1 := csv.NewReader(f1)
reader2 := csv.NewReader(f2)
lineNum := 1
for {
record1, err1 := reader1.Read()
record2, err2 := reader2.Read()
if err1 == io.EOF && err2 == io.EOF {
break
}
if !equalRecords(record1, record2) {
fmt.Printf("第%d行存在差异:\n", lineNum)
fmt.Printf("文件1: %v\n", record1)
fmt.Printf("文件2: %v\n", record2)
}
lineNum++
}
return nil
}
func equalRecords(r1, r2 []string) bool {
if len(r1) != len(r2) {
return false
}
for i := range r1 {
if r1[i] != r2[i] {
return false
}
}
return true
}
diffcsv 工具在 csv-utils 生态中填补了 CSV 文件差异比较的空白,与其他工具如 comparecsv、sortcsv 等形成了完整的数据处理工具链。对于内存敏感的大文件场景,建议采用流式处理或分块比较的策略。

