Java实战:指定大小分组压缩文件夹里面的文件案例

简介: 今天给大家分享一个自己写的java实战的小案例,主要功能是实现指定一个文件夹,然后分组压缩里面的文件。其实这个案例还是有一定用途的,比如日志文件夹里面有几千个文件,如果我需要给每个压缩包指定10M,把整个文件夹里面的日志文件都进行压缩,这个案例就能够用得上了。

image_ba17eada.png

一、前言

今天给大家分享一个自己写的java实战的小案例,主要功能是实现指定一个文件夹,然后分组压缩里面的文件。其实这个案例还是有一定用途的,比如日志文件夹里面有几千个文件,如果我需要给每个压缩包指定10M,把整个文件夹里面的日志文件都进行压缩,这个案例就能够用得上了。

废话少说,直接上代码。我这边采用的是最基本的控制台程序,主要还是代码的逻辑有一定的借鉴意义。欢迎大家互相交流学习,如有不妥之处,欢迎指正!

说明:暂时未考虑文件夹里面还有文件夹的情况。

二、代码示例

  1. 新建FileModel.java 实体

主要指定文件名以及文件大小,方便按照大小分组的时候使用。

public class FileModel {
    
      
      
    public FileModel(String name, double fileSize) {
    
      
      
        this.name = name;
        this.fileSize = fileSize;
    }


    // 文件名
    public String name;
    // 文件大小KB
    public double fileSize;


    public String getName() {
    
      
      
        return name;
    }


    public void setName(String name) {
    
      
      
        this.name = name;
    }


    public double getFileSize() {
    
      
      
        return fileSize;
    }


    public void setFileSize(double fileSize) {
    
      
      
        this.fileSize = fileSize;
    }
}
  1. Main.java 代码:

文件夹中文件分组大小采用了递归的方式。

为了实现效果代码都放在了Main.java里面。

具体代码都有注释,直接看注释就行。

private static final double FILE_SIZE=5500; // 指定分组压缩的大小 550KB
    private static final String PATH="D:\\Test; // 指定要处理的文件夹
    public static void main(String[] args) {
    
      
      
        List<FileModel> list = getFiles(PATH);
        HashMap<Double, List<FileModel>> map = new HashMap<>();
        getArr(list,FILE_SIZE,map);
        if(map.size()>0)
        {
    
      
      
            for (Double aDouble : map.keySet()) {
    
      
      
                List<FileModel> fileModels = map.get(aDouble);
                batchZipFiles(fileModels,PATH+"\\"+aDouble.toString()+".zip");
            }
        }
        System.out.println(map);
    }




    // 递归方式实现文件分组
    private static void getArr(List<FileModel> list, double fileSize,Map<Double, List<FileModel>> map) {
    
      
      
        List<FileModel> listAdd = new ArrayList<>();
        if (list.size() > 0) {
    
      
      
            for (FileModel fileModel : list) {
    
      
      
                if (listAdd.size() == 0) {
    
      
      
                    listAdd.add(fileModel);
                } else {
    
      
      


                    if (listAdd.stream().mapToDouble(FileModel::getFileSize).sum() < fileSize) {
    
      
      
                        listAdd.add(fileModel);
                        if(listAdd.size()==list.size())
                        {
    
      
      
                            map.put(listAdd.stream().mapToDouble(FileModel::getFileSize).sum(), listAdd);
                        }
                    } else {
    
      
      
                        // 取差集
                        list = list.stream().filter(item -> !listAdd.contains(item)).collect(Collectors.toList());
                        map.put(listAdd.stream().mapToDouble(FileModel::getFileSize).sum(), listAdd);
                        getArr(list,fileSize,map);
                        break;


                    }
                }
            }
        }


    }


    //读取文件夹获取里面文件的名字尺寸 不考虑嵌套文件夹
    private static List<FileModel> getFiles(String path) {
    
      
      
        List<FileModel> files = new ArrayList<FileModel>();
        File file = new File(path);
        File[] tempList = file.listFiles();
        if (tempList != null && tempList.length > 0) {
    
      
      
            for (File value : tempList) {
    
      
      
                if (value.isFile()) {
    
      
      
                    // System.out.println(value.getName() + ":" + getFileSizeString(value.length()));
                    files.add(new FileModel(
                            value.getName(), getFileSizeKB(value.length())
                    ));
                }
            }
        }
        return files;
    }


    // 获取文件大小KB
    private static double getFileSizeKB(Long size) {
    
      
      
        double length = Double.parseDouble(String.valueOf(size));
        return  length / 1024.0;


    }


    // 返回文件大小尺寸
    private static String getFileSizeString(Long size) {
    
      
      
        double length = Double.parseDouble(String.valueOf(size));
        //如果字节数少于1024,则直接以B为单位,否则先除于1024,后3位因太少无意义
        if (length < 1024) {
    
      
      
            return length + "B";
        } else {
    
      
      
            length = length / 1024.0;
        }
        //如果原字节数除于1024之后,少于1024,则可以直接以KB作为单位
        //因为还没有到达要使用另一个单位的时候
        //接下去以此类推
        if (length < 1024) {
    
      
      
            return Math.round(length * 100) / 100.0 + "KB";
        } else {
    
      
      
            length = length / 1024.0;
        }
        if (length < 1024) {
    
      
      
            //因为如果以MB为单位的话,要保留最后1位小数,
            //因此,把此数乘以100之后再取余
            return Math.round(length * 100) / 100.0 + "MB";
        } else {
    
      
      
            //否则如果要以GB为单位的,先除于1024再作同样的处理
            return Math.round(length / 1024 * 100) / 100.0 + "GB";
        }
    }


    /**
     *  压缩指定文件夹中的所有文件,生成指定名称的zip压缩包
     *
     * @param list 需要压缩的文件名称列表(包含相对路径)
     * @param zipOutPath 压缩后的文件名称
     **/
    public static void batchZipFiles(List<FileModel> list, String zipOutPath) {
    
      
      
        ZipOutputStream zipOutputStream = null;
        WritableByteChannel writableByteChannel = null;
        MappedByteBuffer mappedByteBuffer = null;
        try {
    
      
      
            zipOutputStream = new ZipOutputStream(new FileOutputStream(zipOutPath));
            writableByteChannel = Channels.newChannel(zipOutputStream);


            File file = new File(PATH);
            File[] tempList = file.listFiles();
            List<String> fileList = list.stream().map(FileModel::getName).collect(Collectors.toList());
            File[] addList=new File[fileList.size()];
            assert tempList != null;
            for (File file1 : tempList) {
    
      
      
                if(fileList.contains(file1.getName()))
                {
    
      
      
                    long fileSize = file1.length();
                    //利用putNextEntry来把文件写入
                    zipOutputStream.putNextEntry(new ZipEntry(file1.getName()));
                    long read = Integer.MAX_VALUE;
                    int count = (int) Math.ceil((double) fileSize / read);
                    long pre = 0;
                    //由于一次映射的文件大小不能超过2GB,所以分次映射
                    for (int i = 0; i < count; i++) {
    
      
      
                        if (fileSize - pre < Integer.MAX_VALUE) {
    
      
      
                            read = fileSize - pre;
                        }
                        mappedByteBuffer = new RandomAccessFile(file1, "r").getChannel()
                                .map(FileChannel.MapMode.READ_ONLY, pre, read);
                        writableByteChannel.write(mappedByteBuffer);
                        pre += read;
                    }
                }
            }
            assert mappedByteBuffer != null;
            mappedByteBuffer.clear();
        } catch (Exception e) {
    
      
      


        } finally {
    
      
      
            try {
    
      
      
                if (null != zipOutputStream) {
    
      
      
                    zipOutputStream.close();
                }
                if (null != writableByteChannel) {
    
      
      
                    writableByteChannel.close();
                }
                if (null != mappedByteBuffer) {
    
      
      
                    mappedByteBuffer.clear();
                }
            } catch (Exception e) {
    
      
      


            }
        }
    }

三、展示效果

最终运行效果如下

image_fe27d76d.png

四、最后

本案例实现了指定分组大小压缩的功能,仅供参考学习交流,欢迎大神指正,提出更好的算法。高手勿喷!

相关文章
|
7天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
25 2
|
4天前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
|
11天前
|
存储 缓存 安全
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见。本文介绍了使用 `File.createTempFile` 方法和自定义创建临时文件的两种方式,详细探讨了它们的使用场景和注意事项,包括数据缓存、文件上传下载和日志记录等。强调了清理临时文件、确保文件名唯一性和合理设置文件权限的重要性。
28 2
|
19天前
|
jenkins Java 测试技术
如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例详细说明
本文介绍了如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例,详细说明了从 Jenkins 安装配置到自动构建、测试和部署的全流程。文中还提供了一个 Jenkinsfile 示例,并分享了实践经验,强调了版本控制、自动化测试等关键点的重要性。
53 3
|
20天前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
|
21天前
|
存储 Java API
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
27 4
|
21天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
39 2
|
24天前
|
Java 数据格式 索引
使用 Java 字节码工具检查类文件完整性的原理是什么
Java字节码工具通过解析和分析类文件的字节码,检查其结构和内容是否符合Java虚拟机规范,确保类文件的完整性和合法性,防止恶意代码或损坏的类文件影响程序运行。
|
24天前
|
Java API Maven
如何使用 Java 字节码工具检查类文件的完整性
本文介绍如何利用Java字节码工具来检测类文件的完整性和有效性,确保类文件未被篡改或损坏,适用于开发和维护阶段的代码质量控制。
|
22天前
|
Java 关系型数据库 数据库
面向对象设计原则在Java中的实现与案例分析
【10月更文挑战第25天】本文通过Java语言的具体实现和案例分析,详细介绍了面向对象设计的五大核心原则:单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则帮助开发者构建更加灵活、可维护和可扩展的系统,不仅适用于Java,也适用于其他面向对象编程语言。
14 2
下一篇
无影云桌面