You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

迭代处理后清除列表对象,解决CSV重复写入问题求助

问题分析与修复方案

嗨,我来帮你梳理下代码里的问题,以及怎么修复:


首先说核心问题:重复写入的根源

你现在所有文件内容相同,本质是匹配过的OutputCsvDataDto对象没有从outputDataList中移除,导致每个文件遍历的时候,都能匹配到全部对象,自然写入的内容一模一样。

另外你的嵌套循环逻辑完全绕反了:

  • 遍历每个文件时,又从头遍历所有addressLists和outputDataList,这会让同一个对象被反复匹配
  • 还有processFile里的对象赋值逻辑明显写错了,这会导致outputDataList里的对象数据根本不对

先修正processFile里的低级错误

你这段代码的赋值逻辑完全有问题:

this.csvOut = new OutputCsvDataDto();
this.csvOut=set.data ; // 这行是把csvOut的引用改成了set.data,不是给对象属性赋值!
this.csvOut=set.value ; // 又把引用改成了set.value,之前新建的OutputCsvDataDto直接被丢弃了

正确的做法应该是给新建的对象的属性赋值,而且尽量用局部变量,避免成员变量带来的混乱:

public void processFile(Mapper mapper) {
    List<OutputCsvDataDto> outputDataList = new ArrayList<>();
    Iterator<List<AddressDto>> iter = this.addressLists.iterator();
    
    while (iter.hasNext()) {
        List<AddressDto> listOfAddress = iter.next();
        for (AddressDto address : listOfAddress) {
            // 用局部变量,不要用成员变量this.csvOut,避免循环中引用混乱
            OutputCsvDataDto csvOut = new OutputCsvDataDto();
            // 这里改成你实际的属性赋值,比如:
            csvOut.setData(/* 对应的数据 */);
            csvOut.setValue(/* 对应的值 */);
            // 一定要把当前address关联到csvOut上,否则后续匹配不了
            csvOut.setAddress(address);
            // 把对象加入列表
            outputDataList.add(csvOut);
        }
    }
    // 等所有数据都准备好,再调用写入方法
    processDataToResultantCsv(outputDataList);
}

重构processDataToResultantCsv实现预期逻辑

我们要实现的是:每个文件写入一批匹配的对象,写完后把这些对象从列表中移除,后续文件不会再处理它们。这里必须用迭代器来安全移除元素,否则会抛出ConcurrentModificationException:

public void processDataToResultantCsv(List<OutputCsvDataDto> outputDataList) {
    Iterator<String> filesIterator = this.getOutgoingFileName().iterator();
    
    while (filesIterator.hasNext()) {
        String fileName = filesIterator.next();
        // 先收集当前文件要写入的所有数据
        List<OutputCsvDataDto> dataForCurrentFile = new ArrayList<>();
        
        // 遍历所有地址,匹配对应的输出对象
        for (List<AddressDto> addressList : this.addressLists) {
            for (AddressDto address : addressList) {
                // 用迭代器遍历outputDataList,这样可以安全移除元素
                Iterator<OutputCsvDataDto> outputIter = outputDataList.iterator();
                while (outputIter.hasNext()) {
                    OutputCsvDataDto output = outputIter.next();
                    if (address.equals(output.getAddress())) {
                        dataForCurrentFile.add(output);
                        outputIter.remove(); // 匹配到就立即从原列表移除,避免后续文件重复写入
                        break; // 每个address只匹配一个output,找到就跳出循环
                    }
                }
            }
        }
        
        // 只有当有数据的时候才写入文件
        if (!dataForCurrentFile.isEmpty()) {
            this.writer.writeToCsv(dataForCurrentFile, fileName);
        }
        
        // 移除已经处理过的文件名
        filesIterator.remove();
    }
}

几个关键的改进点

  1. 安全移除元素:用Iterator.remove()来移除outputDataList中的元素,这是集合遍历中修改元素的标准方式,不会触发并发修改异常。
  2. 避免重复匹配:一旦某个OutputCsvDataDto被匹配并加入当前文件的列表,就立即从原列表移除,后续文件遍历的时候就找不到它了。
  3. 批量写入:先收集当前文件需要的所有数据,再一次性写入,比循环多次调用writeToCsv效率更高。
  4. 修复对象赋值:在processFile中用局部变量创建OutputCsvDataDto,并正确给属性赋值,确保outputDataList中的数据是正确的。

内容的提问来源于stack exchange,提问作者user9193174

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:17:56