内存和硬盘中的 Zip 不同,导致下载后 Zip 损坏

问题描述 投票:0回答:1

大家好我想实现一个zip下载。我有一个网络应用程序,用户可以单击按钮:

<template>
  <button name="exportButton" id="exportButton" @click="convertConfigurationToZip" :class="['button']">{{
      exportConfig
    }}
  </button>
</template>

methods: {
    async convertConfigurationToZip() {
      // Stores the current config in "store.config"
      RestResource.convertConfigurationToZip();

      const configData = store.config;
      await new Promise((resolve) => setTimeout(resolve, 2000));

      // A Blob represents raw binary data
      const blob = new Blob([configData], {type: 'application/zip'});

      // Use file-saver to trigger the download
      saveAs(blob, 'ProCAKE_Configuration')

RestResource中调用的函数如下:

convertConfigurationToZip: () => {
        axios
            .get("http://localhost:8080/api/conversion/convertConfigurationToZip/")
            .then((response: any) => {
                console.log(response.data);
                store.config = response.data;
            })
            .catch((error: any) => {
                console.log(error);
            })
    }

被调用的控制器如下所示:

package controller;

import io.swagger.annotations.*;
import jakarta.annotation.Resource;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.container.AsyncResponse;
import jakarta.ws.rs.container.Suspended;
import jakarta.ws.rs.core.Response;
import services.ConversionService;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

// This Controller should be used for creating zip files that contains the ProCake-Configuration
@Api(tags = "Conversion Controller", authorizations = { @Authorization(value = "basicAuth") })
@Path("/conversion")
public class ConversionController
{
    @Resource
    ExecutorService executorService;

    @ApiOperation(value = "Convert Config into Zip")
    @ApiResponses({ @ApiResponse(code = 200, message = "Config as Zip"), @ApiResponse(code = 503, message = "ProCAKE not started/configured properly") })
    @GET
    @Path("/convertConfigurationToZip")
    public void convertConfigurationToZip(@Suspended final AsyncResponse response)
    {
        executorService = Executors.newSingleThreadExecutor();
        executorService.submit(() ->
        {
            try
            {
                response.resume(Response.status(200).entity(new ConversionService().convertConfigurationToZip()).build());
            }
            catch (Exception e)
            {
                response.resume(e);
            }
            executorService.shutdown();
        });
    }
}

处理 Zip 文件的服务如下所示:

package services;

import de.uni_trier.wi2.procake.data.model.Model;
import de.uni_trier.wi2.procake.data.model.ModelFactory;
import de.uni_trier.wi2.procake.similarity.SimilarityModel;
import de.uni_trier.wi2.procake.similarity.SimilarityModelFactory;
import de.uni_trier.wi2.procake.utils.io.IOUtil;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.jena.sparql.exec.RowSet;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipInputStream;

public class ConversionService
{
    public byte[] convertConfigurationToZip() throws IOException
    {
        try
        {
            // Create Zip on Harddrive
            List<File> listOfFiles = new ArrayList<File>();
            File hello = new File("pathToFile");
            File world = new File("pathToFile");
            listOfFiles.add(hello);
            listOfFiles.add(world);
            IOUtil.createZipFile("pathToZip", listOfFiles);
            // ---------------------

            // Create Zip File in Memory
               ByteArrayOutputStream baos = IOUtil.createZipFileInMemory(listOfFiles);
;
            // ---------------------

            // Compare both Zip Files
            byte[] zipContentHardDrive = Files.readAllBytes(Paths.get("pathToFile"));
            byte[] zipContentMemory = baos.toByteArray();

            int minLength = Math.min(zipContentMemory.length, zipContentHardDrive.length);

            if (!Arrays.equals(
                            Arrays.copyOf(zipContentMemory, minLength),
                            Arrays.copyOf(zipContentHardDrive, minLength))) {
                throw new IOException("The Zip Files are different.");
            }
            // ---------------------

            return zipContentMemory;
        }catch (Exception e) {
            System.out.println("Could not create Zip File");
        }
        return null;
    }
}

最后,在我详细介绍我的问题之前,这里是 IOUtil 方法:

public static ByteArrayOutputStream createZipFileInMemory(List<File> files) throws IOException {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(
        byteArrayOutputStream);

    for (File file : files) {
      addZipEntry(zipArchiveOutputStream, file);
    }

    zipArchiveOutputStream.finish();
    return byteArrayOutputStream;
  }
private static void addZipEntry(ArchiveOutputStream archiveOutputStream, File file)
      throws IOException {
    String entryName = file.getName();
    ArchiveEntry archiveEntry = new ZipArchiveEntry(file, entryName);
    archiveOutputStream.putArchiveEntry(archiveEntry);
    if (file.isFile()) {
      Files.copy(file.toPath(), archiveOutputStream);
    }
    archiveOutputStream.closeArchiveEntry();
  }

createZipFile 工作完全正常。 我的问题是,我从下载中获得的 zip 文件比我直接在硬盘上创建的文件大 200 字节左右。我也无法打开更大的 zip 文件。用 vim 打开较大的 zip 文件后,我可以看到内容与较小的 zip 文件完全不同:

较小的拉链: " zip.vim 版本 v33 " 浏览 zip 文件路径ToZip " 用光标选择文件并按 ENTER

你好.txt 世界.txt

这是更大的一个: PK^C^D^T^@^H^H^H^@���W^@^@^@^@^@^@^@^@^@^@^@^@ ^@5^@ hello.txtUT^M^@^G���eִ�e���e

我不知道我在内存中创建 zip 文件的方法是否错误,或者传输到 store.config 时是否出现问题。 还有一件事值得注意的是 zipContentHardDrive 和 zipContentMemory 是不同的: zip内容硬盘: [80, 75, 3, 4, 20, 0, 0, 8, 8, 0, -72, -114, -103, 87, 32, 48, 58, 54, 8, 0, 0, 0, 6, 0、0、0、9、0、53、0、104、101、108、108、111、46、116、120、116、85、84、13、0、7、-99、-77、-119 , 101, -42, -76, -119, 101, -99, -77, -119, 101, 10, 0, 32, 0, 0, 0, 0, 0, 1, 0, 24, 0, - 106, 85, -35, -18, 82, 55, -38, 1, 4, 18, -88, -87, 83, 55, -38, 1, -128, 76, -114, -18, 82 , 55, -38, 1, -53, 72, -51, -55, -55, -25, 2, 0, +322 更多]

zip内容内存: [80, 75, 3, 4, 20, 0, 8, 8, 8, 0, -72, -114, -103, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0、0、0、9、0、53、0、104、101、108、108、111、46、116、120、116、85、84、13、0、7、-99、-77、-119 , 101, -42, -76, -119, 101, -99, -77, -119, 101, 10, 0, 32, 0, 0, 0, 0, 0, 1, 0, 24, 0, - 106, 85, -35, -18, 82, 55, -38, 1, 4, 18, -88, -87, 83, 55, -38, 1, -128, 76, -114, -18, 82 , 55, -38, 1, -53, 72, -51, -55, -55, -25, 2, 0, +354 更多]

我不确定是否是这样,因为 zip 文件在内存中和不在内存中时通常是不同的。

如果有人能帮助我理解并解决我的问题,我将非常感激。 非常感谢您抽出时间!

更新1 经过以下测试后,我发现由于未知原因,createZipFileInMemory 方法无法像 CoonversionService 中那样工作。

@Test
  public void testCreateZipFileInMemoryWithFiles() throws IOException {
    IOUtil.writeFile(graph, PATH_GRAPH_TXT);
    IOUtil.writeFile(graph, PATH_GRAPH_XML);

    File fileText = new File(PATH_GRAPH_TXT);
    File fileXML = new File(PATH_GRAPH_XML);

    List<File> listOfFiles = new ArrayList<>();
    listOfFiles.add(fileText);
    listOfFiles.add(fileXML);

    ByteArrayOutputStream zipFileInMemory = IOUtil.createZipFileInMemory(listOfFiles);
    assertNotNull(zipFileInMemory);

    // Now let's check if the data stored in the memory is actually the right Zip-file

    // Therefore let's create an actual Zip-File on our hard drive
    IOUtil.createZipFile(PATH_CREATED_ZIP, listOfFiles);
    
    // Read the content of the created zip file
    byte[] actualZipContent = Files.readAllBytes(Paths.get(PATH_CREATED_ZIP));
    
    // Compare the contents of the files within the zip
    ZipInputStream dataOfMemoryZip = new ZipInputStream(new ByteArrayInputStream(zipFileInMemory.toByteArray()));
    ZipInputStream dataOfHardDriveZip = new ZipInputStream(new ByteArrayInputStream(actualZipContent));

    ZipEntry memoryEntry;
    ZipEntry hardDriveEntry;

    while ((memoryEntry = dataOfMemoryZip.getNextEntry()) != null) {
      hardDriveEntry = dataOfHardDriveZip.getNextEntry();

      assertEquals(memoryEntry.getName(), hardDriveEntry.getName());

      byte[] expectedFileContent = IOUtils.toByteArray(dataOfMemoryZip);
      byte[] actualFileContent = IOUtils.toByteArray(dataOfHardDriveZip);

      assertArrayEquals(expectedFileContent, actualFileContent);
    }
  }

这里的内容总是一样的。我不明白为什么 ConversionService 类中的内容不同,因为我使用相同的文件和相同的方法。

java axios download zip
1个回答
0
投票

您创建的 zip 文件的部分十进制转储确实不同。

zipContentMemory
已创建 streamed zip 文件,而
zipContentHarddrive
尚未创建。这足以解释为什么一个 zip 文件可以工作,而另一个却不能。

注意:如果没有看到完整的 zip 文件,就不可能 100% 确定这一点。 zip 文件中可能存在一些其他差异,导致您遇到问题。如果有机会的话,发布完整的 zip 转储。

部分

zipContentHarddrive
zip 文件看起来像这样

0000 LOCAL HEADER #1       04034B50 (67324752)
0004 Extract Zip Spec      14 (20) '2.0'
0005 Extract OS            00 (0) 'MS-DOS'
0006 General Purpose Flag  0800 (2048)
     [Bits 1-2]            0 'Normal Compression'
     [Bit 11]              1 'Language Encoding'
0008 Compression Method    0008 (8) 'Deflated'
000A Last Mod Date/Time    57E6F1C7 (1474752967) 'Invalid Date or Time'
000E CRC                   363A3020 (909783072)
0012 Compressed Size       00000008 (8)
0016 Uncompressed Size     00000006 (6)
001A Filename Length       0009 (9)
001C Extra Length          0035 (53)
001E Filename              'hello.txt'
0027 Extra ID #1           5455 (21589) 'Extended Timestamp [UT]'
0029   Length              000D (13)
002B   Flags               07 (7) 'mod access change'
002C   Mod Time            65F6CCE2 (1710673122) 'Sun Mar 17 10:58:42 2024'
0030   Access Time         65F6CBA9 (1710672809) 'Sun Mar 17 10:53:29 2024'
0034   Change Time         65F6CCE2 (1710673122) 'Sun Mar 17 10:58:42 2024'
0038 Extra ID #2           000A (10) 'NTFS FileTimes'
003A   Length              0020 (32)
003C   Reserved            00000000 (0)
0040   Tag1                0001 (1)
0042   Size1               0018 (24)
0044   Mtime               01A5375291A255E9 (118561792965367273) 'Thu Sep 16 07:08:16 1976 536727300ns'
004C   Atime               01A53753D6D71204 (118561798421418500) 'Thu Sep 16 07:17:22 1976 141850000ns'
0054   Ctime               01A5375291F14CFF (118561792970542335) 'Thu Sep 16 07:08:17 1976 54233500ns'

部分

zipContentMemory
zip 文件看起来像这样

0000 LOCAL HEADER #1       04034B50 (67324752)
0004 Extract Zip Spec      14 (20) '2.0'
0005 Extract OS            00 (0) 'MS-DOS'
0006 General Purpose Flag  0808 (2056)
     [Bits 1-2]            0 'Normal Compression'
     [Bit  3]              1 'Streamed'
     [Bit 11]              1 'Language Encoding'
0008 Compression Method    0008 (8) 'Deflated'
000A Last Mod Date/Time    57E6F1C7 (1474752967) 'Invalid Date or Time'
000E CRC                   00000000 (0)
0012 Compressed Size       00000000 (0)
0016 Uncompressed Size     00000000 (0)
001A Filename Length       0009 (9)
001C Extra Length          0035 (53)
001E Filename              'hello.txt'
0027 Extra ID #1           5455 (21589) 'Extended Timestamp [UT]'
0029   Length              000D (13)
002B   Flags               07 (7) 'mod access change'
002C   Mod Time            65F6CCE2 (1710673122) 'Sun Mar 17 10:58:42 2024'
0030   Access Time         65F6CBA9 (1710672809) 'Sun Mar 17 10:53:29 2024'
0034   Change Time         65F6CCE2 (1710673122) 'Sun Mar 17 10:58:42 2024'
0038 Extra ID #2           000A (10) 'NTFS FileTimes'
003A   Length              0020 (32)
003C   Reserved            00000000 (0)
0040   Tag1                0001 (1)
0042   Size1               0018 (24)
0044   Mtime               01A5375291A255E9 (118561792965367273) 'Thu Sep 16 07:08:16 1976 536727300ns'
004C   Atime               01A53753D6D71204 (118561798421418500) 'Thu Sep 16 07:17:22 1976 141850000ns'
0054   Ctime               01A5375291F14CFF (118561792970542335) 'Thu Sep 16 07:08:17 1976 54233500ns'
© www.soinside.com 2019 - 2024. All rights reserved.