【问题标题】:Zip ByteArray decompression returns null but input stream is validZip ByteArray 解压返回 null 但输入流有效
【发布时间】:2020-04-15 17:30:04
【问题描述】:

所以我试图将一个 csv 文件压缩到内存中,将其作为 BLOB 存储在 MYSQL 中,然后获取并解压缩它,但是 ZipInputStream.getEntry 返回 null 并且我真的无法解压缩该文件,我尝试了一切并我真的找不到答案。 我第一次使用 GZIP 压缩/解压缩文件并工作,但它改变了 CSV 文件结构,所以这就是我尝试使用 Zip 的原因。 CSV 文件是通过 Spring 的 MultipartFile.getBytes() 从前端接收的。

这是从 DB 看到的压缩文件头 (标题似乎有效)

00000000  50 4B 03 04 14 00 08 08 08 00 B4 A0 8F 50 00 00    PK........´ .P..

提前致谢!

压缩方式:

@Throws(Exception::class)
fun compressFile(file : ByteArray) : ByteArray {
    val baos = ByteArrayOutputStream()
    val zos = ZipOutputStream(baos)
    val entry = ZipEntry("data.csv")
    entry.size = file.size.toLong()
    zos.putNextEntry(entry)
    zos.write(file)
    zos.closeEntry()
    zos.close()
    return baos.toByteArray()
}

解压方式:

@Throws(Exception::class)
fun decompressFile(file : ByteArray): ByteArray {
   if (file.isEmpty()) return file
   val gis = ZipInputStream(ByteArrayInputStream(file))
   val bf = BufferedReader(InputStreamReader(gis, "UTF-8"))
   var outStr = ""
   var line: String
   while (bf.readLine().also { line = it ?: "" } != null) {
       outStr += line
   }
   gis.close()
   bf.close()
   return outStr.toByteArray()
}

The ZipInputStream object after init

【问题讨论】:

  • 你从不打电话给getNextEntry(),所以你认为你正在阅读哪个邮编?
  • @Andreas 我不需要调用 getNextEntry 因为我直接从流中读取(至少 GZIP 以这种方式工作),但我也尝试了 getNetEntry 并且它返回 null,你可以检查我链接的图像下面使用创建的 ZipInputStream 对象。
  • GZIP 不是 ZIP。 --- 不知道图像显示什么。这是你打电话给getNextEntry()之前或之后的状态吗?
  • @Andreas 好的,那么如果 ZipInputStream 条目为空,我如何将文件解压缩为字节数组?
  • @Andreas 或者至少为什么 GZIP 会更改我的 CSV 文件?用gzip压缩前的文件是header1,header2,header3 new line val1,val2,val3 压缩后 -> header1,header2,header3val1,val2,val3

标签: java file csv kotlin compression


【解决方案1】:

要阅读ZipInputStream,您必须在阅读前致电getNextEntry()

对于这个例子,我创建了一个包含 2 个文件的 zip 文件:

  • foo.text 内容为 Foo Bar
  • hello.txt 内容为Hello World

以下代码显示在调用 getNextEntry() 之前尝试读取将不会产生任何结果:

public static void main(String[] args) throws Exception {
    try (ZipInputStream zip = new ZipInputStream(new FileInputStream("C:\\Temp\\foo.zip"))) {
        BufferedReader reader = new BufferedReader(new InputStreamReader(zip, "UTF-8"));

        // read before getNextEntry() finds nothing
        printText(reader);

        ZipEntry zipEntry;
        while ((zipEntry = zip.getNextEntry()) != null) {
            System.out.println("Entry Name: " + zipEntry.getName() + "   Size: " + zipEntry.getSize());

            // read after getNextEntry() finds only the entry's content
            printText(reader);
        }
    }
}
static void printText(BufferedReader reader) throws IOException {
    int count = 0;
    for (String line; (line = reader.readLine()) != null; count++)
        System.out.println("  " + line);
    System.out.println(count + " lines");
}

输出

0 lines
Entry Name: foo.txt   Size: 7
  Foo Bar
1 lines
Entry Name: hello.txt   Size: 11
  Hello World
1 lines

【讨论】:

  • 有效!我假设如果对象中的“条目”属性为空并且条目大小为-1,则数据未被正确读取。但是现在我又回到了 GZIP 的问题上,我有一个 CSV,最初是 header1,header2,heeader3 (new line) val1, val2, val3 (new line) val4,val5,val6 (standard csv format, first line列标题,然后是行),但压缩后文件为 header1、header2、heeader3val1、val2、val3val4、val5、val6(没有新行,我无法按原样重新制作文件/
  • @Vlad 这个问题是关于ZipInputStream 的,已经得到解答。如果您对 GZIP 有疑问,那是另一个问题,因此请创建一个新问题,并包含一个 Minimal, Reproducible Example,以证明您断言它会更改内容,并且不是 您的 代码在做这件事。 --- 每个问题只有一个问题/问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-21
  • 1970-01-01
  • 2017-11-26
  • 2016-10-06
  • 1970-01-01
  • 2021-06-07
相关资源
最近更新 更多