Go语言文件检查追加问题:循环致数据异常如何解决?
问题分析与修复方案
原代码的逻辑错误点
- 重复打开同一文件且内容不同步:同时打开
fileWrite和fileRead两个句柄,fileRead读取的是文件打开时的静态快照,后续通过fileWrite追加的内容无法被fileRead获取,导致检查逻辑永远基于旧数据。 - 文件指针未重置:第一次扫描完文件后,
fileRead的指针停在文件末尾,后续循环创建scannerRead时,无法重新遍历整个文件,直接返回扫描结束状态。 - 无效的写入判断:
if scannerRead.Scan() == false完全多余,前面已经完成全文件扫描,此时scannerRead必然处于末尾,这个条件永远成立,没有实际判断意义。 - 未适配
tx.Data的动态变化:外层is_Cursor循环中,tx.Data可能被修改,但内层循环的i < len(tx.Data)基于循环启动时的长度,无法处理过程中新增的元素。 - 资源浪费与同步风险:重复创建
bufio.Scanner且未复用,两个句柄操作同一文件可能引发数据同步问题。
正确实现方案
核心思路:每次处理tx.Data前,先读取文件最新内容到内存集合(实现快速查找),遍历tx.Data检查元素是否存在,不存在则追加到文件;同时适配tx.Data的动态变化,用动态遍历逻辑处理。
package main import ( "bufio" "log" "os" "strings" ) func checkAndAppend(fileName string, tx *Tx, maxMemoryTx int) { // 用单个文件句柄完成读写,避免同步问题,同时添加O_CREATE确保文件不存在时自动创建 file, err := os.OpenFile(fileName, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644) if err != nil { log.Fatalln(err) } defer file.Close() // 外层循环,对应原逻辑中的is_Cursor循环 for { // 重置文件指针到开头,读取最新内容到内存集合 file.Seek(0, 0) existingItems := make(map[string]struct{}) scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line != "" { existingItems[line] = struct{}{} } } if err := scanner.Err(); err != nil { log.Fatal(err) } // 处理tx.Data,最多处理maxMemoryTx个元素 processedCount := 0 // 用索引遍历,适配tx.Data可能的动态长度变化 for i := 0; i < len(tx.Data) && processedCount < maxMemoryTx; i++ { target := strings.TrimSpace(tx.Data[i].Type) if target == "" { continue } // 检查是否已存在,不存在则追加 if _, exists := existingItems[target]; !exists { if _, err := file.WriteString(target + "\n"); err != nil { log.Fatal(err) } // 更新内存集合,避免下次重复检查 existingItems[target] = struct{}{} } processedCount++ } // 替换为实际的is_Cursor判断逻辑,比如检查是否还有新的tx数据需要处理 // if !is_Cursor { // break // } } } // 假设Tx和TxData的定义如下(根据实际场景调整) type Tx struct { Data []TxData } type TxData struct { Type string }
实现说明
- 单句柄操作:使用一个文件句柄完成读写,通过
file.Seek(0, 0)重置指针,确保每次读取的是文件最新内容。 - 高效查找:用
map[string]struct{}存储已存在的元素,O(1)时间复杂度完成存在性检查,比逐行扫描效率更高。 - 动态数据适配:每次循环前重新读取文件,遍历
tx.Data时记录处理数量,适配数据动态变化的场景。 - 无效内容过滤:去除行首尾空白,避免空行或无效内容被存入集合。
内容的提问来源于stack exchange,提问作者Tommaso Ceredi
相关产品推荐
相关产品推荐

