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

解决Java文件移动时的NoSuchFileException异常问题

CSV文件移动时出现NoSuchFileException的修复方案

问题背景

使用Java代码遍历指定目录下的CSV文件,根据文件中匹配的值将其移动到对应子目录,但执行时抛出文件不存在异常。

原始代码

@Override
public void execute(JobExecutionContext context) {

    File directoryPath = new File("C:\\csv\\nov");
    // Create a new subfolder called "processed" into source directory
    try {
        Path processedFolderPath = Path.of(directoryPath.getAbsolutePath() + "/processed");
        if (!Files.exists(processedFolderPath) || !Files.isDirectory(processedFolderPath)) {
            Files.createDirectory(processedFolderPath);
        }

        Path invalidFilesFolderPath = Path.of(directoryPath.getAbsolutePath() + "/invalid_files");
        if (!Files.exists(invalidFilesFolderPath) || !Files.isDirectory(invalidFilesFolderPath)) {
            Files.createDirectory(invalidFilesFolderPath);
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }

    FilenameFilter textFileFilter = (dir, name) -> {
        String lowercaseName = name.toLowerCase();
        if (lowercaseName.endsWith(".csv")) {
            return true;
        } else {
            return false;
        }
    };
    // List of all the csv files
    File filesList[] = directoryPath.listFiles(textFileFilter);
    System.out.println("List of the text files in the specified directory:");

    for(File file : filesList) {

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

                for (CsvLine item : beans)
                {
                    Path originalPath = file.toPath();
                    if(item.getValue().equals(2)
                    || item.getValue().equals(43)
                    || item.getValue().equals(32))
                    {
                        // Move here file into new subdirectory when file is invalid
                        Path copied = Paths.get(file.getParent() + "/invalid_files");
                        try {
                            // Use resolve method to keep the "processed" as folder
                            br.close();
                            Files.move(originalPath, copied.resolve(originalPath.getFileName()), StandardCopyOption.REPLACE_EXISTING);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                }}
        } catch (Exception e){
            e.printStackTrace();
        }
        Path originalPath = file.toPath();
        System.out.println(String.format("\nProcessed file : %s, moving the file to subfolder /processed\n",
                originalPath));
    }

    // Move here file into new subdirectory when file processing is finished
                        Path copied = Paths.get(file.getParent() + "/processed");
                        try {
                            // Use resolve method to keep the "processed" as folder
                            br.close();
                            Files.move(originalPath, copied.resolve(originalPath.getFileName()), StandardCopyOption.REPLACE_EXISTING);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
}

错误信息

java.lang.RuntimeException: java.nio.file.NoSuchFileException: C:\csv\nov\12_21_39.csv
      at com.wordscore.engine.processor.DataValidationCheckJob.execute(DataValidationCheckJob.java:94)
      at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
      at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
    Caused by: java.nio.file.NoSuchFileException: C:\csv\nov\12_21_39.csv

问题分析

  1. 重复移动文件:当文件被判定为无效并移动到invalid_files目录后,后续代码仍尝试将同一个文件移动到processed目录,此时原文件已不存在,抛出异常。
  2. 代码结构错误:最后一段移动到processed的代码位于for循环外部,且变量file、br、originalPath不在该作用域内,属于语法错误。
  3. 流操作冗余:在try-with-resources块内手动调用br.close(),违背了自动资源管理的设计。
  4. CSV行遍历逻辑问题:只要有一行匹配就移动文件,但未终止循环,可能导致多次尝试移动同一个文件。

修复后的代码

@Override
public void execute(JobExecutionContext context) {
    File directoryPath = new File("C:\\csv\\nov");
    Path processedFolderPath = directoryPath.toPath().resolve("processed");
    Path invalidFilesFolderPath = directoryPath.toPath().resolve("invalid_files");

    // 创建目标目录
    try {
        if (!Files.exists(processedFolderPath)) {
            Files.createDirectories(processedFolderPath);
        }
        if (!Files.exists(invalidFilesFolderPath)) {
            Files.createDirectories(invalidFilesFolderPath);
        }
    } catch (IOException e) {
        throw new RuntimeException("创建目录失败", e);
    }

    // 筛选CSV文件
    FilenameFilter csvFilter = (dir, name) -> name.toLowerCase().endsWith(".csv");
    File[] filesList = directoryPath.listFiles(csvFilter);
    
    // 处理空目录情况
    if (filesList == null || filesList.length == 0) {
        System.out.println("指定目录下无CSV文件");
        return;
    }

    System.out.println("待处理的CSV文件列表:");
    for (File file : filesList) {
        boolean isInvalid = false;
        Path originalPath = file.toPath();
        System.out.println("- " + originalPath.getFileName());

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

            // 检查是否存在匹配的行
            for (CsvLine item : beans) {
                Integer value = item.getValue();
                if (value != null && (value.equals(2) || value.equals(43) || value.equals(32))) {
                    isInvalid = true;
                    break; // 找到匹配后终止循环,避免重复判断
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            isInvalid = true; // 解析失败的文件也视为无效
        }

        // 根据标记移动文件
        try {
            Path targetPath;
            if (isInvalid) {
                targetPath = invalidFilesFolderPath.resolve(originalPath.getFileName());
                Files.move(originalPath, targetPath, StandardCopyOption.REPLACE_EXISTING);
                System.out.println("文件已移动到invalid_files: " + originalPath.getFileName());
            } else {
                targetPath = processedFolderPath.resolve(originalPath.getFileName());
                Files.move(originalPath, targetPath, StandardCopyOption.REPLACE_EXISTING);
                System.out.println("文件已移动到processed: " + originalPath.getFileName());
            }
        } catch (IOException e) {
            throw new RuntimeException("移动文件失败: " + originalPath, e);
        }
    }
}

修复说明

  • 新增状态标记:用isInvalid变量标记文件是否无效,避免重复移动操作。
  • 调整代码结构:将文件移动逻辑整合到for循环内,确保每个文件只被移动一次。
  • 优化路径处理:使用Path.resolve()替代字符串拼接,避免路径格式错误。
  • 自动资源管理:移除手动关闭流的操作,依赖try-with-resources自动关闭。
  • 异常处理增强:解析失败的文件直接标记为无效,同时完善异常信息。
  • 空目录处理:提前判断文件列表是否为空,避免空指针异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 03:05:50