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
相关产品推荐
相关产品推荐

