我有一个想要序列化的对象:
@Serializable
class Test(
override val name: String,
override val data: ByteArray
) {
fun toBytes(): ByteArray = Json.encodeToString(this).encodeToByteArray()
}
这显然将
data
序列化为 ByteArray 的字符串表示形式。
// assume data = "test".toByteArray()
// then the serialized object will be
{
"name": "somename"
"data": "[116,101,115,116]"
}
现在将
data
从 4 字节变成 17 字节。如何正确序列化这些数据?我宁愿将 data
保留为 ByteArray
,而不是尝试将 data
变为 String
编辑: 回复@sweeper: 很难解释我的意思,但最终的序列化对象可能如下所示:
"{
\"name\": \"somename\",
\"data\":".toByteArray() +
data
+ "\"}".toByteArray()
我希望 Kotlin 能够有一个类似的机制,它可以将 ByteArray“粘贴”到位。
是的,我可以更改整个代码以使用 Base64,但这不是我要问的。
在这种情况下,如果数据很大,你要做的就是将数据与 json 一起存储。基本上是一种混合方法。它是一个 PIA,因为您可能必须自己构建一个(我正在这样做)。
基本上使用 C/C++ 中的标准方法将二进制数据存储在文件顶部(我正在编写一个二进制序列化器,它只为 Kotlin 执行此操作,可以插入,但我有边走边学)。这可能需要一些额外的结构,但可以通过仅使用文件写入来手动完成(跟踪结构是 PIA 部分,这就是我正在研究二进制序列化的原因)。
如果您知道要序列化的所有数组类型,那么我要做的就是简单地为它们创建一个自定义序列化器
您也可以使用 cbor。这可能需要对您的课程进行一些预处理。
然后基本上使用 cbor 将二进制数据写入文件的顶部(或底部),然后将 json 写入底部。将位置存储到 json 位置以便于检索。
或者,您可以直接写出字节,但您必须修补并为数据数组编写自定义序列化器(这并不困难,但使用起来很混乱。
如果你可以处理cbor,那么就使用cbor。 IMO,使用 json 的唯一原因是使编辑文件变得容易,这就是我选择这样做的原因(在我的情况下它仍然有效,因为我正在压缩数组)。
// To be able to serialize ByteArray: Annotate with @Serializable(with = ByteArraySerializer::class)
object ByteArraySerializer : KSerializer<ByteArray> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ByteArray", PrimitiveKind.STRING)
@OptIn(ExperimentalSerializationApi::class)
override fun serialize(encoder: Encoder, value: ByteArray) { encoder.encodeString(value.size.toString() + ":" + value.contentHashCode()) }
override fun deserialize(decoder: Decoder): ByteArray { return decoder.decodeString().toByteArray() }
}
例如,给出 { “数据测试1”:“0:1”, “数据测试2”:“52:1577655441” }
对于
@Serializable(with = ByteArraySerializer::class) var dataTest1: ByteArray = emptyArray<Byte>().toByteArray(),
@Serializable(with = ByteArraySerializer::class) var dataTest2: ByteArray = ByteArray(52).apply { this[0] = 53; this[22] = 123 }
您可以只存储空绳子或水
这个想法是,在解码 json 后,你必须返回并填写存储在其他地方的缺失信息。
如果您使用 cbor 存储数据,那么这很容易,除了您必须以某种方式使 cbor 和 json 不相交(不确定是否可以为特定序列化器或类型进行注释)。
如果您可以使用两个文件,那么您可以先使用 json 部分,然后使用 cbor 部分,如果您可以使 json 的序列化与 cbor 不相交,那么使用它几乎是无缝的
或者,您可以直接使用一些 hacky 的东西对数据进行编码,但它不会是有效的 json。例如,您可以使用上面的代码,但只需让它写出 ByteArray 的字节和长度以及一些要搜索的 id/token。然后,当您加载 json 时,您必须将字节数组替换为更短的正确版本,以便序列化器正确解码,然后将其替换为原始字节。
无论哪种方式你都赢不了。 Json 应该有一个类似“blob”的类型,可以让你直接使用字节,但他们没有,而且不可能添加它,因为它会破坏每个 json 解析器。