Kotlin gzip解压缩失败

时间:2020-07-21 11:15:36

标签: java android kotlin gzip

我尝试将我的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;
  }

这是我的kotlin代码。

  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.

减压过程似乎被读者打断了?

2 个答案:

答案 0 :(得分:1)

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

使用readBytes()获取Char,它与JVM平台中的ByteArray表示相同。

示例:

byte[]

编辑:

对于读取字节,您不应该使用GZIPInputStream(payload.inputStream()) .bufferedReader() .use { it.readBytes() } ,它的目的是读取Kotlin的Reader中定义的UTF-8格式的文本:

InputStream.bufferedReader

InputStream.readBytes()会在8KB的缓冲区中读取字节。

public inline fun InputStream.bufferedReader(charset: Charset = Charsets.UTF_8): BufferedReader = reader(charset).buffered()

所以您只需要做:

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
}

答案 1 :(得分:0)

使用以下功能:

<publish-subscribe-channel>

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

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

}

希望这会有所帮助??