Java读取txt入库PostgreSQL后如何删除源文件已处理行
逐行处理后删除源文件已处理行的实现方案
Java 没有提供直接删除文本文件指定行的原生API,因为文本文件是顺序存储的字节序列,直接原位修改中间内容很容易覆盖后续数据,造成文件损坏。生产环境优先采用临时文件中转+原子替换的方案,兼顾数据安全和实现简单性,完全避免程序崩溃、IO异常导致的数据丢失问题。
前置注意事项
- 只有数据库插入操作事务提交成功后,才能标记对应行为已处理,不要在
save()方法刚执行、事务还未提交时就移除行,避免事务回滚造成数据丢失 - 文件操作优先用
try-with-resources语法自动释放流资源,避免文件句柄泄漏 - 处理过程中出现异常时,不要替换原文件,保证未处理成功的行下次运行时可以重新处理
实现逻辑
- 定义原文件路径,以及同目录下的临时文件路径
- 逐行读取原文件内容,执行原有数据库校验、插入逻辑
- 插入成功的行不写入临时文件(等价于从待处理列表删除),未处理成功、无需插入的行按需求写入临时文件保留
- 所有行处理完成后,删除原文件,将临时文件重命名为原文件名(同分区下文件重命名是原子操作,不会产生中间损坏状态)
改造后的可运行代码
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
相关产品推荐
相关产品推荐

