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

Java读取txt入库PostgreSQL后如何删除源文件已处理行

逐行处理后删除源文件已处理行的实现方案

Java 没有提供直接删除文本文件指定行的原生API,因为文本文件是顺序存储的字节序列,直接原位修改中间内容很容易覆盖后续数据,造成文件损坏。生产环境优先采用临时文件中转+原子替换的方案,兼顾数据安全和实现简单性,完全避免程序崩溃、IO异常导致的数据丢失问题。

前置注意事项

  • 只有数据库插入操作事务提交成功后,才能标记对应行为已处理,不要在save()方法刚执行、事务还未提交时就移除行,避免事务回滚造成数据丢失
  • 文件操作优先用try-with-resources语法自动释放流资源,避免文件句柄泄漏
  • 处理过程中出现异常时,不要替换原文件,保证未处理成功的行下次运行时可以重新处理

实现逻辑

  1. 定义原文件路径,以及同目录下的临时文件路径
  2. 逐行读取原文件内容,执行原有数据库校验、插入逻辑
  3. 插入成功的行不写入临时文件(等价于从待处理列表删除),未处理成功、无需插入的行按需求写入临时文件保留
  4. 所有行处理完成后,删除原文件,将临时文件重命名为原文件名(同分区下文件重命名是原子操作,不会产生中间损坏状态)

改造后的可运行代码

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.Optional;

// 类定义省略,仅展示核心处理逻辑
public void processFileAndInsert() {
    String sourceFilePath = "C:\\in_progress\\test.txt";
    // 同目录创建临时文件,避免跨分区移动的性能问题
    String tempFilePath = "C:\\in_progress\\test_temp.txt";
    File sourceFile = new File(sourceFilePath);
    File tempFile = new File(tempFilePath);

    // 用try-with-resources自动关闭读写流,无需手动close
    try (
        BufferedReader reader = new BufferedReader(new FileReader(sourceFile));
        BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))
    ) {
        String line = reader.readLine();
        while (line != null) {
            // 跳过空行,可按需调整
            if (line.isBlank()) {
                line = reader.readLine();
                continue;
            }
            System.out.println("处理行内容: " + line);
            Thread.sleep(100);
            boolean processSuccess = false;

            try {
                Optional<ProcessedWords> isFound = processedWordsService.findByKeyword(line);
                if (!isFound.isPresent()) {
                    ProcessedWords obj = ProcessedWords.builder()
                            .keyword(line)
                            .createdAt(LocalDateTime.now())
                            .build();
                    // 注意:如果是Spring事务环境,要确保这里save执行完事务已提交,再标记成功
                    processedWordsService.save(obj);
                    // 如果需要仅删除本次成功插入的行、已存在的关键词行保留,就把processSuccess = true放在这里
                }
                // 走到这里说明该行处理完成(无论是新增插入还是已存在),标记为成功
                processSuccess = true;
            } catch (Exception e) {
                // 数据库操作出错,打印异常,该行保留待下次重试
                e.printStackTrace();
            }

            // 处理失败的行写入临时文件保留,处理成功的行不写入(即被删除)
            if (!processSuccess) {
                writer.write(line);
                writer.newLine();
            }

            line = reader.readLine();
        }
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
        // 文件读写出错,直接终止流程,不替换原文件,清理残留临时文件
        tempFile.delete();
        return;
    }

    try {
        // 删除原文件,把临时文件重命名为原文件
        Files.deleteIfExists(sourceFile.toPath());
        Files.move(tempFile.toPath(), Paths.get(sourceFilePath));
    } catch (IOException e) {
        e.printStackTrace();
        // 替换失败时删除临时文件,避免残留垃圾文件
        tempFile.delete();
    }
}

不推荐的方案说明

不要使用RandomAccessFile做原位删除修改:文本行长度不固定时,删除一行需要将后续所有字节整体前移覆盖,大文件场景性能极差,且中途程序崩溃会直接损坏原文件,没有恢复可能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 08:12:31