You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlinx Serialization解析ByteArray报错,如何实现JSON转ByteArray?

问题

从服务器拿到的JSON数据里,audio字段是字符串形式的二维字节数组(示例:"audio": "[[22, 124, 78, ...], [233, 89, 112, ...]]"),用Kotlinx Serialization解析成List<ByteArray>时触发报错:

Unexpected JSON token at offset 902: Failed to parse 'byte'

当前代码:

import kotlinx.serialization.Serializable

@Serializable
data class ServerResponse(
    val audio: List<ByteArray>
)

需要把这个字段正确转成List<ByteArray>,方便用File.writeBytes()写入文件。

解决方案

问题根源是Kotlinx Serialization默认的ByteArray序列化器只认Base64编码格式,但服务器返回的是字符串包裹的数字数组,得自定义序列化器来适配这种格式。

1. 写一个ByteArray的自定义序列化器

这个序列化器负责把"[22,124,78]"这类字符串解析成ByteArray,也能反向把ByteArray转成对应格式的字符串:

import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

object StringToByteArraySerializer : KSerializer<ByteArray> {
    override val descriptor: SerialDescriptor =
        PrimitiveSerialDescriptor("StringToByteArray", PrimitiveKind.STRING)

    override fun serialize(encoder: Encoder, value: ByteArray) {
        val stringValue = value.joinToString(prefix = "[", postfix = "]", separator = ", ")
        encoder.encodeString(stringValue)
    }

    override fun deserialize(decoder: Decoder): ByteArray {
        val stringValue = decoder.decodeString()
        // 去掉首尾的[],分割成单个数字字符串后转成Byte数组
        return stringValue.trim('[', ']')
            .split(",")
            .map { it.trim().toByte() }
            .toByteArray()
    }
}

2. 再写List<ByteArray>的自定义序列化器

因为服务器返回的是二维数组的字符串,得先把外层字符串拆成子数组的字符串列表,再逐个用上面的序列化器处理:

import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

object StringToListByteArraySerializer : KSerializer<List<ByteArray>> {
    private val delegate = ListSerializer(StringToByteArraySerializer)

    override val descriptor: SerialDescriptor = delegate.descriptor

    override fun serialize(encoder: Encoder, value: List<ByteArray>) {
        val stringValue = value.joinToString(prefix = "[", postfix = "]") { byteArray ->
            byteArray.joinToString(prefix = "[", postfix = "]", separator = ", ")
        }
        encoder.encodeString(stringValue)
    }

    override fun deserialize(decoder: Decoder): List<ByteArray> {
        val stringValue = decoder.decodeString()
        // 去掉首尾的[],按"], ["分割成子数组字符串,再清理每个子数组的首尾[]
        val subArrays = stringValue.trim('[', ']')
            .split("], [")
            .map { it.trim('[', ']') }
        // 把每个子数组字符串转成ByteArray
        return subArrays.map { subStr ->
            subStr.split(",")
                .map { it.trim().toByte() }
                .toByteArray()
        }
    }
}

3. 在数据类里用上自定义序列化器

修改ServerResponse,给audio字段指定我们写的序列化器:

import kotlinx.serialization.Serializable

@Serializable
data class ServerResponse(
    @Serializable(with = StringToListByteArraySerializer::class)
    val audio: List<ByteArray>
)

4. 验证使用

解析完成后,就能正常遍历audio列表并写入文件了:

// 假设已经解析得到serverResponse实例
serverResponse.audio.forEachIndexed { index, byteArray ->
    File("audio_$index.bin").writeBytes(byteArray)
}

注意点

  • 如果服务器返回的数字超出Byte的范围(大于127或小于-128),toByte()会抛异常,要么提前和服务器确认数据范围,要么改成toInt().toByte()做截断处理。
  • 如果字符串格式有特殊情况(比如空格不统一、多余字符),得在deserialize方法里加对应的清洗逻辑。

内容的提问来源于stack exchange,提问作者WiseEye

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 15:20:33