Golang Go语言中如何实现文件对比功能,按文本固定一列为关联列对比其他列并输出不同内容以及各自缺失的关联列

发布于 1周前 作者 bupafengyu 来自 Go语言

Golang Go语言中如何实现文件对比功能,按文本固定一列为关联列对比其他列并输出不同内容以及各自缺失的关联列
对这个需求,我举个栗子如下:
文件 1 和文件 2 均含有客户 ID、客户年龄以及客户地址,要找出以下 3 种数据:
1、客户在文件 1、文件 2 都存在,但是地址或年龄至少有一个属性不同(变化数据)
2、客户在文件 1 中存在,但是文件 2 中不存在(新增数据)
3、客户在文件 2 中存在,但是文件 1 中不存在(删除数据)

大概意思就是这样。这个需求实际上用数据库的话很好解决,但是碍于环境限制,无法将数据装载入数据库中再进行关联对比 /(ㄒoㄒ)/~~,必须直接在外部进行对比。每天处理的文件大概在 800G 左右,文件数量大概在 200 左右,最大文件大概在 50G 左右,设备为 8Core CPU,内存 32G。文件比较大,对性能也有一些要求。随意想请教大家,是否有什么好的实现思路,如何对比能够高效。非常感谢大家~


更多关于Golang Go语言中如何实现文件对比功能,按文本固定一列为关联列对比其他列并输出不同内容以及各自缺失的关联列的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

13 回复

直接用 diff 能够处理吗?

更多关于Golang Go语言中如何实现文件对比功能,按文本固定一列为关联列对比其他列并输出不同内容以及各自缺失的关联列的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


直接用 diff 的话,需要解析 diff 输出内容,会比较麻烦

先外部 sort 排序之后,然后两个文件同时读着处理下? 不过文件有点大,不太确定 sort 命令的性能。

不能用数据库就学学数据库怎么做的呗
文件 1 文件 2 都按年龄分桶,然后每个桶对应的去比较呗
你地址格式化的好的话也可以先按地址分桶再按年龄分桶,然后随便搞个 hash 查找就行了
或者你可以用 pandas…

pandas 加载太大的文件内存就撑不住了 orz

分好桶之后再用呗

哦哦,那你可以这样做,先把两个文件按照客户 id 做外排序。然后利用类似于归并排序的归并过程。

我给你准备了一个简单的 sample:

$ cat before.txt
Smith 26 Beijing
Sam 47 Washington
Mary 15 Tokyo

$ cat after.txt
Smith 26 Beijing
Sam 57 Washington
Nancy 21 Paris

这个 Sample 里,新增了 Nancy,删除了 Mary,修改了 Sam。

先做外排序:

$ sort -k1 before.txt > sorted_before.txt
$ sort -k1 after.txt > sorted_after.txt

然后利用归并过程来实现你的需求,具体是这样的:

两个迭代器或者指针 fp_before, fp_after 分别指向 sorted_before.txt 和 sorted_after.txt 的第一行,进行如下迭代:

1. 如果 before_key > after_key,说明 after 中的第一行是新增的,输出结果,fp_after 移动到下一行
2. 如果 before_key < after_key,如果 before 中的第一行被删除了,输出结果,fp_before 移动到下一行
3. 如果 before_key == after_key,两个指针都移动下一行,但是移动前先对比当前两条记录,如果不一致,说明修改了

迭代完后,如果 fp_before 没有到文件末尾,那么剩下的内容都会被删除的记录;如果 fp_after 没有到末尾,那么剩下的内容都会新增的记录。

很遗憾,我不会 Go,用 Python3 写了份代码供你参考,时间有限写得不好请见谅:

#!/usr/env/python3
# -- coding: utf-8 --

with open(“sorted_before.txt”) as fp_before, <br> open(“sorted_after.txt”) as fp_after:

before = fp_before.readline()
after = fp_after.readline()

while before and after:
before = before.rstrip()
after = after.rstrip()

before_key = before.split()[0]
after_key = after.split()[0]

if after_key < before_key:
print("+", after)
after = fp_after.readline()

elif after_key > before_key:
print("-", before)
before = fp_before.readline()

else:
if before != after:
print(’ ', before, “=>”, after)
before = fp_before.readline()
after = fp_after.readline()

for before_surplus in fp_before:
print("-", before_surplus)

for after_surplus in fp_after:
print("+", after_surplus)

这份代码跑上面的 sample 的结果:

- Mary 15 Tokyo
+ Nancy 21 Paris
Sam 47 Washington => Sam 57 Washington

Python 的缩进粘贴过来没有了,我给个 gist 吧: https://gist.github.com/dongyx/a052cadf160896b879cdfb4d48e2f038

typo:

2. 如果 before_key < after_key,如果 before 中的第一行被删除了,输出结果,fp_before 移动到下一行

=>

2. 如果 before_key < after_key,说明 before 中的第一行被删除了,输出结果,fp_before 移动到下一行

我用 go 实现以下,非常感谢~

你那边试了吗?能不能解决问题?我对这个问题挺感兴趣的,很希望能得到你的后续反馈。

抱歉由于工作原因,我这边还没有抽出时间实现这个对比,后续待我完成给您后续反馈,非常感谢~

在Go语言中实现文件对比功能,特别是按文本固定一列为关联列对比其他列,并输出不同内容及各自缺失的关联列,可以遵循以下步骤:

  1. 读取文件:使用os.Openbufio.NewReader读取文件内容,将每行存储到一个切片中。

  2. 解析文件:按行解析文件内容,将每行按指定分隔符(如逗号、空格等)拆分为字段,并存储为结构体或map,其中关联列作为键。

  3. 对比文件:使用map或哈希表来存储第一个文件的数据,以便快速查找。然后遍历第二个文件,对于每个关联列,检查是否存在于第一个文件的map中。如果存在,则对比其他列的内容;如果不存在,则记录为缺失。

  4. 输出结果:根据对比结果,输出不同内容及各自缺失的关联列。可以使用fmt.Printlnfmt.Printf格式化输出。

示例代码框架:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func main() {
    // 读取并解析文件1和文件2
    file1Data, err := readFile("file1.txt")
    // 处理错误
    file2Data, err := readFile("file2.txt")
    // 处理错误

    // 对比文件
    compareFiles(file1Data, file2Data)
}

// readFile, compareFiles 函数需自行实现,包括解析、对比和输出逻辑。

注意,具体实现需考虑文件格式、错误处理、性能优化等因素。

回到顶部