Kotlin gzip 解压缩失败

Kotlin gzip uncompress fail

我尝试将我的 java gzip 解压缩代码简化为 kotlin。但是我改了之后还是坏了

这是java代码

  public static byte[] uncompress(byte[] compressedBytes) {
    if (null == compressedBytes || compressedBytes.length == 0) {
      return null;
    }

    ByteArrayOutputStream out = null;
    ByteArrayInputStream in = null;
    GZIPInputStream gzipInputStream = null;

    try {
      out = new ByteArrayOutputStream();
      in = new ByteArrayInputStream(compressedBytes);
      gzipInputStream = new GZIPInputStream(in);
      byte[] buffer = new byte[256];
      int n = 0;

      while ((n = gzipInputStream.read(buffer)) >= 0) {
        out.write(buffer, 0, n);
      }

      return out.toByteArray();
    } catch (IOException ignore) {
    } finally {
      CloseableUtils.closeQuietly(gzipInputStream);
      CloseableUtils.closeQuietly(in);
      CloseableUtils.closeQuietly(out);
    }

    return null;
  }

这是我的科特林代码。

  payload = GZIPInputStream(payload.inputStream())
      .bufferedReader()
      .use { it.readText() }
      .toByteArray()

我遇到了这个错误。

com.google.protobuf.nano.InvalidProtocolBufferNanoException: While parsing a protocol message, the input ended unexpectedly in the middle of a field.  This could mean either than the input has been truncated or that an embedded message misreported its own length.

解压过程好像被reader打断了?

readText(charset: Charset = Charsets.UTF_8) 将字节解码为 UTF-8 字符集,这就是为什么它说“这可能意味着输入已被截断”它可能试图将 8 位转换为 Char 并从中构建一个字符串。

使用readBytes()得到ByteArray,在JVM平台中表示与byte[]相同。

示例:

GZIPInputStream(payload.inputStream())
      .bufferedReader()
      .use { it.readBytes() }

编辑:

对于读取字节,您不应该使用 Reader,它用于读取 Kotlin 的 InputStream.bufferedReader:

中定义的 UTF-8 格式的文本
public inline fun InputStream.bufferedReader(charset: Charset = Charsets.UTF_8): BufferedReader = reader(charset).buffered()

InputStream.readBytes() 将读取 8KB 缓冲区本身的字节。

public fun InputStream.readBytes(): ByteArray {
    val buffer = ByteArrayOutputStream(maxOf(DEFAULT_BUFFER_SIZE, this.available()))
    copyTo(buffer)
    return buffer.toByteArray()
}
// This copies with 8KB buffer automatically
// DEFAULT_BUFFER_SIZE = 8 * 1024
public fun InputStream.copyTo(out: OutputStream, bufferSize: Int = DEFAULT_BUFFER_SIZE): Long {
    var bytesCopied: Long = 0
    val buffer = ByteArray(bufferSize)
    var bytes = read(buffer)
    while (bytes >= 0) {
        out.write(buffer, 0, bytes)
        bytesCopied += bytes
        bytes = read(buffer)
    }
    return bytesCopied
}

所以你只需要做:

GZIPInputStream(payload.inputStream()).use { it.readBytes() }

使用以下函数:

    fun File.unzip(unzipLocationRoot: File? = null) {

    val rootFolder = unzipLocationRoot
        ?: File(parentFile.absolutePath + File.separator + nameWithoutExtension)
    if (!rootFolder.exists()) {
        rootFolder.mkdirs()
    }

    ZipFile(this).use { zip ->
        zip
            .entries()
            .asSequence()
            .map {
                val outputFile = File(rootFolder.absolutePath + File.separator + it.name)
                ZipIO(it, outputFile)
            }
            .map {
                it.output.parentFile?.run {
                    if (!exists()) mkdirs()
                }
                it
            }
            .filter { !it.entry.isDirectory }
            .forEach { (entry, output) ->
                zip.getInputStream(entry).use { input ->
                    output.outputStream().use { output ->
                        input.copyTo(output)
                    }
                }
            }
    }

}

将文件作为参数传递如下:

val zipFile = File(your file directory, your file name)
            zipFile.unzip()

希望这会有所帮助