Java 전투: 압축 폴더의 파일 크기 지정

함께 만들고 함께 성장하기 위해 함께 노력하십시오! "너겟 데일리 뉴플랜 · 8월 업데이트 챌린지" 참여 22일차 입니다 . 이벤트 상세보기 클릭

I. 소개

오늘은 제가 직접 작성한 ava 실제 전투의 작은 사례를 공유하겠습니다. 주요 기능은 폴더를 지정한 다음 그 안에 파일을 그룹화하고 압축하는 것입니다. 사실 이 경우도 나름의 용도가 있는데, 예를 들어 로그 폴더에 수천 개의 파일이 있다. 압축된 패키지마다 10M을 지정하고 전체 폴더에 로그 파일을 압축해야 하는 경우 이 경우를 사용할 수 있다. 말도 안되는 소리하지 말고 코드로 직접 이동하십시오. 내가 여기서 사용하는 것은 가장 기본적인 콘솔 프로그램입니다. 주로 코드의 논리에 특정 참조 의미가 있기 때문입니다. 서로 교환하고 배우는 것을 환영합니다. 잘못된 것이 있으면 저를 수정하십시오!

참고: 당분간 폴더에 폴더가 있는 상황은 고려하지 않습니다.

2. 코드 예제

  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) {


            }
        }
    }
复制代码

3. 디스플레이 효과

최종 작업 효과는 다음과 같습니다.

넷째, 마지막

이 경우는 그룹 크기 압축을 지정하는 기능을 구현합니다.참고 및 학습 교환만을 위한 것입니다.저를 수정하고 더 나은 알고리즘을 제안하는 것을 환영합니다. 전문가는 스프레이하지 않습니다!

코드 주소: gitee.com/hgm1989/fil…

추천

출처juejin.im/post/7132638265491849230