讲师中心 微信公众号
AI工具推荐 视频效率加速

如何正确移动文件以避免 NoSuchFileException 错误

阿浩酱_5845

阿浩酱_5845

发布时间:2026-02-02 14:37:02

|

750人浏览过

|

来源于php中文网

原创

如何正确移动文件以避免 NoSuchFileException 错误

本文详解因循环中重复调用 files.move() 导致文件被多次移动、触发 nosuchfileexception 的根本原因,并提供结构清晰、资源安全的修复方案,确保每个 csv 文件仅被移动一次到对应目标目录。

在您提供的 Quartz 定时任务代码中,核心问题并非路径错误或权限缺失,而是逻辑控制缺陷:for (CsvLine item : beans) 循环内未及时退出,导致同一文件在满足条件后被多次尝试移动 —— 第二次移动时源文件已不存在,从而抛出 java.nio.file.NoSuchFileException。

? 问题定位:重复移动是罪魁祸首

原始代码中:

if(item.getValue().equals(2) || ...) {
    Path copied = Paths.get(file.getParent() + "/invalid_files");
    Files.move(originalPath, copied.resolve(...)); // ✅ 第一次成功移动
}
// ❌ 缺少 break;循环继续 → 下一轮 item 再次触发 move → 源文件已不存在!

由于未使用 break 中断循环,只要 beans 列表中存在多个匹配项(或后续迭代),就会对同一个 originalPath 多次执行 Files.move()。而 Files.move() 是原子性操作:首次成功后源文件即被移走,第二次必然失败。

js2java
js2java

JavaScript 到 Java 全栈翻译助手,专为前端开发者学习 Java 或快速实现后端业务逻辑而设计。当用户提到以下场景时必须使用此技能: - "帮我把这段 JS 代码转成 Java" - "用 Java 怎么写这个逻辑" - "我习惯用 JS 写,想翻译成 Java" - "教我 Java,我要写后端接...

下载

此外,代码中还存在 资源管理隐患:手动调用 br.close() 并置于 try-with-resources 块内部,违反了自动资源管理原则,易引发 IllegalStateException 或掩盖真实异常。

✅ 推荐修复方案:单次决策 + 统一移动

以下是重构后的健壮实现,遵循“先判断归类、再统一移动”原则,逻辑清晰且线程安全:

@Override
public void execute(JobExecutionContext context) {
    File directoryPath = new File("C:\csv\nov");

    // 创建目标子目录(processed / invalid_files)
    try {
        Path processedDir = Path.of(directoryPath.getAbsolutePath(), "processed");
        Path invalidDir = Path.of(directoryPath.getAbsolutePath(), "invalid_files");

        Files.createDirectories(processedDir);   // createDirectories 安全创建多级目录
        Files.createDirectories(invalidDir);
    } catch (IOException e) {
        throw new RuntimeException("Failed to create directories", e);
    }

    // 过滤 CSV 文件
    FilenameFilter csvFilter = (dir, name) -> name.toLowerCase().endsWith(".csv");
    File[] csvFiles = directoryPath.listFiles(csvFilter);
    if (csvFiles == null) {
        System.out.println("No CSV files found in directory.");
        return;
    }

    for (File file : csvFiles) {
        Path originalPath = file.toPath();
        Path targetPath = Path.of(file.getParent(), "processed", file.getName()); // 默认移至 processed

        try (FileReader br = new FileReader(file, StandardCharsets.UTF_16)) {
            List<CsvLine> beans = new CsvToBeanBuilder<>(br)
                    .withType(CsvLine.class)
                    .withSeparator('	')
                    .withSkipLines(3)
                    .build()
                    .parse();

            // 遍历检测:只要发现任一非法值,即标记为 invalid 并跳出循环
            for (CsvLine item : beans) {
                Integer value = item.getValue();
                if (value != null && (value.equals(2) || value.equals(43) || value.equals(32))) {
                    targetPath = Path.of(file.getParent(), "invalid_files", file.getName());
                    System.out.printf("⚠️  Invalid value %d found in %s → will move to invalid_files%n", 
                            value, file.getName());
                    break; // ✅ 关键:立即终止检测,避免重复 move
                }
            }
        } catch (Exception e) {
            // 解析失败视为异常文件,归入 invalid_files
            targetPath = Path.of(file.getParent(), "invalid_files", file.getName());
            System.err.printf("❌ Parsing failed for %s: %s → moved to invalid_files%n", 
                    file.getName(), e.getMessage());
        }

        // ✅ 统一执行移动(无论 valid/invalid/parse-error)
        try {
            Files.move(originalPath, targetPath, StandardCopyOption.REPLACE_EXISTING);
            System.out.printf("✅ Moved %s → %s%n", file.getName(), targetPath.getParent().getFileName());
        } catch (IOException e) {
            throw new RuntimeException("Failed to move file: " + file.getName(), e);
        }
    }
}

⚠️ 关键改进说明

  • 单次判定,统一移动:将移动逻辑完全移出数据解析循环,在 try-with-resources 外统一执行,彻底杜绝重复移动。
  • break 确保早停:一旦确认文件为 invalid,立即 break,不进行冗余遍历。
  • 异常文件兜底处理:catch (Exception) 中将解析失败的文件也归入 invalid_files,提升鲁棒性。
  • createDirectories() 替代 createDirectory():自动创建父目录(如 invalid_files 不存在时),避免 NoSuchFileException 在目录创建阶段发生。
  • 日志分级输出:使用 System.out.printf 和 System.err.printf 区分正常流程与错误信息,便于运维排查。

? 补充建议

  • 若 CSV 文件极大,可考虑使用 Files.lines() 流式读取前几行做快速校验,避免全量解析。
  • 生产环境建议集成 SLF4J 日志框架替代 System.out,并添加 MDC 追踪 Job 执行上下文。
  • 对于高并发场景,可在 move 前加 Files.exists(originalPath) 双重检查(虽非必需,但可增强防御性)。

通过以上重构,您的任务将稳定运行,不再因逻辑漏洞触发 NoSuchFileException,同时代码可读性、可维护性与健壮性均显著提升。

热门AI工具

更多
Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

相关专题

更多
Java I/O 与 NIO 编程体系合集
Java I/O 与 NIO 编程体系合集

全面讲解 Java I/O 编程的演进与核心 API,涵盖传统 I/O 的字节流(InputStream/OutputStream)与字符流(Reader/Writer)体系、装饰器模式在 I/O 中的应用(BufferedReader/InputStreamReader)、文件读写与目录操作、NIO 核心三要素(Buffer 缓冲区/Channel 通道/Selector 选择器)、ByteBuffer 操作与内存映射文件(Mappe

412

2026.04.29

printf用法大全
printf用法大全

php中文网为大家提供printf用法大全,以及其他printf函数的相关文章、相关下载资源以及各种相关课程,供大家免费下载体验。

788

2023.06.20

fprintf和printf的区别
fprintf和printf的区别

fprintf和printf的区别在于输出的目标不同,printf输出到标准输出流,而fprintf输出到指定的文件流。根据需要选择合适的函数来进行输出操作。更多关于fprintf和printf的相关文章详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1029

2023.11.28

java中break的作用
java中break的作用

本专题整合了java中break的用法教程,阅读专题下面的文章了解更多详细内容。

2720

2025.10.15

java break和continue
java break和continue

本专题整合了java break和continue的区别相关内容,阅读专题下面的文章了解更多详细内容。

767

2025.10.24

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

4178

2023.08.10

OpenJDK JVM参数怎么调优
OpenJDK JVM参数怎么调优

Java应用运行缓慢,如何调整JVM参数?本专题介绍OpenJDK JVM性能调优的基本流程,涵盖性能指标确认、运行数据采集、内存配置和垃圾回收分析,帮助你先定位瓶颈,再通过对照测试验证效果,避免直接套用参数而影响应用稳定性。

20

2026.10.16

OpenJDK怎么配置Java开发环境
OpenJDK怎么配置Java开发环境

怎样用OpenJDK搭建开发环境?本专题介绍版本选择、下载安装、环境变量配置和编译运行验证,帮助你理清JDK的作用及基本配置流程,并通过简单程序检查环境是否可用,为后续项目开发做好准备。

20

2026.10.16

OpenJDK怎么部署Java应用
OpenJDK怎么部署Java应用

Java项目开发完成后,怎样部署到目标环境并正常运行?本专题介绍OpenJDK应用部署流程,涵盖运行环境准备、版本兼容检查、应用打包、启动参数配置和日志查看,帮助你理清部署前后的操作顺序,减少环境差异造成的运行问题。

20

2026.10.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn