java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java文件过滤

使用Java实现文件大小过滤功能(附源码)

作者:Katie。

在实际开发中,经常需要对大量文件进行批量处理,对于这些场景,开发者往往需要根据文件的大小进行筛选,本文就来利用Java实现文件大小过滤功能,有需要的可以了解下

一、项目背景详细介绍

在实际开发中,经常需要对大量文件进行批量处理,如日志清理、备份管理、数据迁移等。对于这些场景,开发者往往需要根据文件的大小进行筛选:将超过指定阈值的大文件单独归档,或者将过小的临时文件删除,以节省存储空间、提升系统性能或增强数据安全性。

因此,实现一个“Java 文件大小过滤”工具,能够灵活地根据用户指定的大小阈值,对目录或文件列表进行扫描、筛选与分类,具有重要的实用价值。

二、项目需求详细介绍

本项目的目标是设计并实现一个通用的 Java 文件大小过滤模块,主要需求包括:

1.阈值条件

2.扫描范围

3.输出格式

4.性能与并发

5.易用性与扩展

对外提供静态工具类 FileSizeFilter,方法签名示例:

public static List<File> filterBySize(File directory, long minBytes, long maxBytes);

支持命令行执行 java -jar filesizefilter.jar --min 10MB --max 1GB --path /data/logs

后续可扩展结合日期、文件类型、名称模式等更多过滤条件。

6.异常与日志

三、相关技术详细介绍

为满足以上需求,将涉及并运用以下核心技术与类库:

1.Java 文件 I/O 与 NIO

2.并发与线程池

3.命令行解析

4.序列化与导出

5.日志框架

SLF4J + Logback:记录扫描进度、错误文件及异常堆栈,支持日志级别控制。

6.单元测试

四、实现思路详细介绍

结合需求与技术,项目的实现思路可以分为以下几个步骤:

1.阈值解析

2.文件扫描

3.并发执行

4.结果排序与导出

5.命令行入口

6.错误处理与日志

五、完整实现代码

// ============================================================================
// 文件:SizeParser.java
// 包名:com.example.filesizefilter
// 功能:将用户输入的大小阈值字符串(如 "1.5GB"、"1024KB")解析为字节数
// ============================================================================
package com.example.filesizefilter;

import java.util.regex.*;
import com.example.filesizefilter.exception.FilterException;

public class SizeParser {
    // 支持单位:B、KB、MB、GB(大小写均可)
    private static final Pattern PATTERN = Pattern.compile(
        "\\s*([0-9]+(?:\\.[0-9]+)?)\\s*(B|KB|MB|GB)?\\s*", Pattern.CASE_INSENSITIVE);

    /**
     * 将字符串表示的大小转换为字节数
     * @param sizeStr 大小字符串,如 "512MB", "1.5 GB", "1024"
     * @return 对应的字节数
     */
    public static long parse(String sizeStr) {
        Matcher m = PATTERN.matcher(sizeStr);
        if (!m.matches()) {
            throw new FilterException("无法解析大小阈值:" + sizeStr);
        }
        double value = Double.parseDouble(m.group(1));
        String unit = m.group(2);
        if (unit == null || unit.equalsIgnoreCase("B")) {
            return (long) value;
        } else if (unit.equalsIgnoreCase("KB")) {
            return (long) (value * 1024L);
        } else if (unit.equalsIgnoreCase("MB")) {
            return (long) (value * 1024L * 1024L);
        } else if (unit.equalsIgnoreCase("GB")) {
            return (long) (value * 1024L * 1024L * 1024L);
        } else {
            throw new FilterException("不支持的单位:" + unit);
        }
    }
}

// ============================================================================
// 文件:FilterResult.java
// 包名:com.example.filesizefilter
// 功能:封装过滤后文件及其大小信息
// ============================================================================
package com.example.filesizefilter;

import java.io.File;

public class FilterResult {
    private final File file;
    private final long size;

    public FilterResult(File file, long size) {
        this.file = file;
        this.size = size;
    }
    public File getFile() { return file; }
    public long getSize() { return size; }
}

// ============================================================================
// 文件:FileSizeFilter.java
// 包名:com.example.filesizefilter
// 功能:核心过滤类,支持按最小、最大阈值对文件或目录递归扫描并行过滤
// ============================================================================
package com.example.filesizefilter;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.concurrent.*;
import com.example.filesizefilter.exception.FilterException;

public class FileSizeFilter {
    /**
     * 按阈值过滤单个文件
     * @param file      文件对象
     * @param minBytes  最小字节数(null 表示不限制)
     * @param maxBytes  最大字节数(null 表示不限制)
     * @return 如果符合条件返回 FilterResult,否则返回 null
     */
    public static FilterResult filter(File file, Long minBytes, Long maxBytes) {
        if (!file.isFile()) {
            throw new FilterException("不是文件:" + file.getPath());
        }
        long size = file.length();
        if ((minBytes == null || size >= minBytes) && (maxBytes == null || size <= maxBytes)) {
            return new FilterResult(file, size);
        }
        return null;
    }

    /**
     * 递归扫描目录并按大小过滤,单线程实现
     */
    public static List<FilterResult> filterDirectory(File dir, Long minBytes, Long maxBytes) {
        if (!dir.isDirectory()) {
            throw new FilterException("不是目录:" + dir.getPath());
        }
        List<FilterResult> results = new ArrayList<>();
        try {
            Files.walkFileTree(dir.toPath(), new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
                    long size = attrs.size();
                    if ((minBytes == null || size >= minBytes) && (maxBytes == null || size <= maxBytes)) {
                        results.add(new FilterResult(path.toFile(), size));
                    }
                    return FileVisitResult.CONTINUE;
                }
                @Override
                public FileVisitResult visitFileFailed(Path path, IOException exc) {
                    // 记录日志并继续
                    System.err.println("无法访问文件:" + path + ",原因:" + exc.getMessage());
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            throw new FilterException("目录扫描失败:" + dir.getPath(), e);
        }
        return results;
    }

    /**
     * 并行扫描多个路径(文件或目录),使用线程池
     */
    public static List<FilterResult> filterPaths(
            List<File> paths, Long minBytes, Long maxBytes, int threadCount) {
        ExecutorService pool = Executors.newFixedThreadPool(threadCount);
        List<Future<List<FilterResult>>> futures = new ArrayList<>();
        for (File path : paths) {
            futures.add(pool.submit(() -> {
                if (path.isDirectory()) {
                    return filterDirectory(path, minBytes, maxBytes);
                } else if (path.isFile()) {
                    FilterResult r = filter(path, minBytes, maxBytes);
                    return r != null ? Collections.singletonList(r) : Collections.emptyList();
                } else {
                    throw new FilterException("路径不存在:" + path.getPath());
                }
            }));
        }
        List<FilterResult> all = new ArrayList<>();
        for (Future<List<FilterResult>> f : futures) {
            try {
                all.addAll(f.get());
            } catch (Exception e) {
                System.err.println("任务执行失败:" + e.getMessage());
            }
        }
        pool.shutdown();
        return all;
    }
}

// ============================================================================
// 文件:Main.java
// 包名:com.example.filesizefilter
// 功能:命令行入口,解析参数、调用过滤逻辑、输出结果(支持排序与格式化导出)
// ============================================================================
package com.example.filesizefilter;

import java.io.*;
import java.util.*;
import com.example.filesizefilter.exception.FilterException;

public class Main {
    private static void printHelp() {
        System.out.println("Usage: java -jar filesizefilter.jar [options] <path1> <path2> ...");
        System.out.println("Options:");
        System.out.println("  --min <size>       最小阈值,如 10MB");
        System.out.println("  --max <size>       最大阈值,如 1GB");
        System.out.println("  -t, --threads <n>  并行线程数,默认 4");
        System.out.println("  -s, --sort <asc|desc>  按大小升序或降序排序,默认 asc");
        System.out.println("  -o, --output <file>    导出结果到文件(CSV 格式),默认输出到控制台");
        System.out.println("  -h, --help         显示帮助信息");
    }

    public static void main(String[] args) {
        if (args.length == 0) { printHelp(); return; }
        Long minBytes = null, maxBytes = null;
        int threads = 4;
        boolean asc = true;
        String outputPath = null;
        List<String> paths = new ArrayList<>();

        for (int i = 0; i < args.length; i++) {
            switch (args[i]) {
                case "--min": minBytes = SizeParser.parse(args[++i]); break;
                case "--max": maxBytes = SizeParser.parse(args[++i]); break;
                case "-t": case "--threads": threads = Integer.parseInt(args[++i]); break;
                case "-s": case "--sort":
                    asc = args[++i].equalsIgnoreCase("asc"); break;
                case "-o": case "--output": outputPath = args[++i]; break;
                case "-h": case "--help": printHelp(); return;
                default: paths.add(args[i]);
            }
        }
        if (paths.isEmpty()) { System.err.println("未指定路径"); printHelp(); return; }

        List<File> fileList = new ArrayList<>();
        for (String p : paths) fileList.add(new File(p));

        try {
            List<FilterResult> results = FileSizeFilter.filterPaths(
                fileList, minBytes, maxBytes, threads);

            // 排序
            results.sort(Comparator.comparingLong(FilterResult::getSize));
            if (!asc) Collections.reverse(results);

            // 输出
            if (outputPath == null) {
                for (FilterResult r : results) {
                    System.out.printf("%s, %d%n", r.getFile().getPath(), r.getSize());
                }
            } else {
                try (PrintWriter pw = new PrintWriter(new FileWriter(outputPath))) {
                    pw.println("文件路径,大小(字节)");
                    for (FilterResult r : results) {
                        pw.printf("%s,%d%n", r.getFile().getPath(), r.getSize());
                    }
                }
                System.out.println("已导出到 " + outputPath);
            }
        } catch (FilterException e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

// ============================================================================
// 文件:FilterException.java
// 包名:com.example.filesizefilter.exception
// 功能:统一异常类型,用于包装解析与过滤过程中的错误
// ============================================================================
package com.example.filesizefilter.exception;

public class FilterException extends RuntimeException {
    public FilterException(String msg) { super(msg); }
    public FilterException(String msg, Throwable cause) { super(msg, cause); }
}

六、代码详细解读

1.SizeParser

2.FilterResult

简单的 POJO,封装被过滤文件 File 对象与其大小 long size,便于统一返回与后续排序、输出处理。

3.FileSizeFilter

4.Main(命令行入口)

5.FilterException

统一封装所有解析与扫描过程中的异常,简化错误处理与信息传播。

七、项目详细总结

本文以“Java 实现文件大小过滤”为主题,设计并实现了一个通用、高性能的文件大小筛选工具。主要包含:

八、项目常见问题及解答

1.如何只指定最小阈值,不限制最大?

在命令行中只传入 --min 参数,不传 --max,即可过滤出所有大于等于该值的文件。

2.目录中文件过多,扫描卡顿怎么办?

可通过 -t 参数增加线程数;或改用更高效的 ForkJoinPool 分支并行模型以提高 I/O 利用率。

3.如何导出为 JSON 格式?

Main 中添加对 --format=json 的支持,使用 Jackson 将 results 序列化为 JSON 并输出。

4.扫描过程中遇到权限不足的文件会如何处理?

filterDirectory 中的 visitFileFailed 会打印错误日志并继续,工具默认忽略不可访问文件,避免中断整个扫描。

5.能否将该模块作为库集成到其他项目?

直接将 SizeParserFileSizeFilter 等类复制到项目中,或打包为 Jar,在 pom.xml 中添加依赖即可使用其 API。

九、扩展方向与性能优化

1.基于 NIO2 异步 I/O

采用 AsynchronousFileChannel 进行非阻塞读取,并结合 CompletableFuture 管理回调,减少阻塞等待;

2.基于 Fork/Join 的分支扫描

将目录拆分为子任务,使用 RecursiveTask 并行调用,提高在多核环境下的扫描速度;

3.更多过滤条件

支持按最后修改时间、文件类型(扩展名/正则匹配)、文件所有者等多维度过滤;

4.导出多种格式

在命令行中加入 --format 选项,可导出 CSV、JSON、XML、HTML 表格等格式,满足不同需求;

5.监控与变更通知

结合 WatchService 实时监控目录中文件变化,并在符合阈值条件时发送邮件、Webhook 通知或日志告警;

6.GUI 图形化工具

基于 Swing 或 JavaFX 开发可视化客户端,用户通过交互界面配置阈值、路径和导出方式;

7.集成定时任务

将工具封装为 Spring Boot 应用,定时执行大小过滤并自动清理或归档,形成完整的文件管理服务。

到此这篇关于使用Java实现文件大小过滤功能(附源码)的文章就介绍到这了,更多相关Java文件过滤内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文