防止从 ZipOutPutStream 中删除重复项

Prevent removing duplicates from ZipOutPutStream

我正在使用这个功能来压缩一堆文件,但问题是如果有两个内容不同但原始名称相同的文件名,那么只有一个文件被压缩,我该如何防止这种情况通过在扩展名前的文件名中添加一个数字,例如file1.txt 重复名称的扩展号码?

     ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())
    
               files.forEach(file -> {

                        final ZipEntry zipEntry = new ZipEntry(Objects.requireNonNull(file.getOriginalName()));
                        zipOut.putNextEntry(zipEntry);
                        IOUtils.copy(file.getInputStream(), zipOut);
                        file.getInputStream().close();
                        zipOut.closeEntry();
}

重复

例如

 files.add("hello");
        files.add("hello");
        files.add("hello");
        files.add("name");
        files.add("name");
        files.add("name");

        files.add("hello22");
        files.add("name");

那么结果应该是

"hello", "hello1", "hello2", "name", "name1", "name2", "name3"

假设您正在创建一个新的 zip 文件而不是编辑现有的 zip 存档,那么您可以遍历 files 列表,如果发现任何重复项,您可以在 HashMap 或类似文件中记下新名称像这样 duplicateNameMap.put(oldNameString, newNameString);,然后在你的 zip 方法中你可以简单地检查 HashMap 并使用更新的名称:

//Hashmap to store updated names
HashMap<String, String> duplicateNameMap = new HashMap<>();

//compare files to each other file to find duplicate names:
for (int i = 0; i < files.size(); i++) {
    for (int j = i+1; j < files.size(); j++) {
        //If duplicate exists then save the new name to the HashMap:
        if(files.get(i).getOriginalName().equals(files.get(j).getOriginalName())) {
            //Use substring to get the file name and extension
            String name = files.get(i).getOriginalName().substring(0, files.get(i).getOriginalName().lastIndexOf("."));
            //If the files have no extension ".doc" etc, then you can remove the next line
            String extension = files.get(i).getOriginalName().substring(files.get(i).getOriginalName().lastIndexOf(".")+1);
            //Use a method to count the number of previous files with the same name and set the correct duplicate number
            String duplicateNumber = fixDuplicateName(files.get(i).getOriginalName());
                
            //Store the new name in a hashmap using the old name as a key
            duplicateNameMap.put(files.get(i).getOriginalName(), name + duplicateNumber + extension));
        }
    }
}

ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream());

//Then when saving files we can check the hashmap and update the files accordingly
files.forEach(file -> {
    String name = file.getOriginalName();
    //Check the HashMap to see if there is a duplicate then get the correct name from the hashmap:
    if (duplicateNameMap.containsKey(file)) {
        //Grab the new name from the hashmap
        String newName = duplicateNameMap.get(name);
        //Remove that entry from the hashmap so that it is not used again
        duplicateNameMap.remove(name, newName);
        //Assign the new name to be used
        name = newName;
    }
    final ZipEntry zipEntry = new ZipEntry(name);
    zipOut.putNextEntry(zipEntry);
    IOUtils.copy(file.getInputStream(), zipOut);
    file.getInputStream().close();
    zipOut.closeEntry();
}

Here is the method used to count the number of duplicates and return the correct duplicate number:

public static String fixDuplicateName(HashMap<String, String> duplicateNameMap, String name) {
    //Start the count at 1 (The first duplicate should always be 1)
    int count = 1;
    //Find out if there is more than 1 duplicate in the hashmap and increase the count if needed
    for (String key: duplicateNameMap.keySet()) {
        if (key.equals(name)) {
            count++;
        }
    }
    return count+"";
}

请注意,这样做的一个小副作用是第一个文件将添加“1”,第二个将添加“2”等,最后一个将是原始名称,但这是几乎不是问题。如果 files 列表中的文件顺序很重要,那么您可以通过将每个名称添加到哈希映射中轻松修复它,即使它不是重复的,然后在 fixDuplicateName 方法中更改 int count = 1;int count = 0; 以便正确标记非重复项。然后在编写 zip 时,只需从 hashmap 中获取每个文件名。