IonWriter
IAP工具中的IonWriter
类(com.nanosai.gridops.ion.write.IonWriter
)可以将ION字段写入字节数组。使用" IonWriter",我们可以自由地编写ION字段,因此要确保我们遵循所编写的ION字段的规则。这也意味着我们可以在封闭环境中违反规则(例如,对于特定数据文件,或者在不向公众开放的两个服务之间交换的消息)。
" IonWriter"包含两组方法。第一组是其实例方法。要使用这些方法,我们必须创建IonWriter
的实例。第二组是" IonWriter"的静态方法。这些可以直接调用而无需IonWriter
实例。
" IonWriter"实例方法比静态方法更易于使用。当我们创建" IonWriter"实例时,我们将" byte"数组设置为所有写入的ION字段的目标。 " IonWriter"会为我们跟踪到目标" byte"数组中的索引。静态方法需要将所有相关信息作为参数传递,例如目标"字节"数组,此数组中的偏移量(用于将ION字段写入)以及要写入的值。
以下各节将说明" IonWriter"的实例方法和静态方法。
IonWriter实例方法
首先,我们将看看" IonWriter"的实例方法,因为它们是最易于使用的。
创建一个IonWriter
要使用" IonWriter"实例方法,我们必须首先创建" IonWriter"实例,并将其添加到目标"字节"数组(写入ION字段的数组)中。这是创建IonWriter
实例的方法:
byte[] dest = new byte[10 * 1024]; IonWriter writer = new IonWriter(dest, 0);
本示例创建一个" IonWriter"实例,将目标" byte"数组和起始偏移量作为参数传递给构造函数。从指定的偏移量开始,所有ION字段都将写入到指定的" byte"数组中。
我们还可以使用setDestination()方法在" IonWriter"上设置目标"字节"数组,如下所示:
byte[] dest = new byte[10 * 1024]; IonWriter writer = new IonWriter(); writer.setDestination(dest, 0);
一旦在" IonWriter"上设置了目标,就可以开始将ION字段写入目标" byte"数组。
writeBytes()
writeBytes()方法将一系列原始字节作为ION Bytes字段写入目标字节数组。这是一个" IonWriter"writeBytes()
示例:
byte[] value = new byte[]{ 1, 2, 3 }; writer.writeBytes(value);
writeBytes()方法还支持将null数组写出,在这种情况下,将写入长度为0的ION Bytes字段(代表一个null Bytes字段)。
writeBoolean()
writeBoolean()方法将Java布尔值作为ION Tiny字段写入目标字节数组。这是一个" IonWriter"的" writeBoolean()"示例:
boolean value = true; writer.writeBoolean(value);
writeBooleanObj()
writeBooleanObj()方法将Java布尔对象作为ION Tiny字段写入目标字节数组。这是一个" IonWriter"的" writeBooleanObj()"示例:
Boolean value = new Boolean(true); writer.writeBooleanObj(value);
writeBooleanObj()方法还支持将null写入,在这种情况下,将写入长度为0的ION Tiny字段(表示null null的Tiny字段)。
writeInt64()
writeInt()方法将Java long(或者其他整数)作为Int64-Positive或者Int64-Negative字段写入目标字节数组。这是一个" IonWriter"的writeInt64()示例:
long value = 123456; writer.writeInt64(value);
writeInt64Obj()
writeInt64Obj()方法将Java Long对象作为Int64-Positive或者Int64-Negative字段写入目标字节数组。这是一个" IonWriter"的writeInt64()示例:
Long value = new Long(123456); writer.writeInt64Obj(value);
writeInt64Obj()方法还支持将null写入,在这种情况下,将写入长度为0的ION Int64-Positive字段(表示一个null的Int64-Positive字段)。
writeFloat32()
" writeFloat32()"方法将Java" float"作为ION Float字段写入目标" byte"数组。这是一个" IonWriter"的writeFloat32()示例:
float value = 123.123f; writer.writeFloat32(value);
writeFloat32Obj()
writeFloat32Obj()方法将Java Float对象作为ION Float字段写入目标字节数组。这是一个" IonWriter"writeFloat32Obj()
示例:
Float value = new Float(123.123f); writer.writeFloat32Obj(value);
writeFloat32Obj()方法还支持将null写入,在这种情况下,将写入长度为0的ION Float字段(表示一个null浮点字段)。
writeFloat64()
writeFloat64()方法将Java double作为ION Float字段写入目标字节数组。这是一个" IonWriter"的writeFloat64()示例:
double value = 123.123d; writer.writeFloat64(value);
writeFloat64Obj()
writeFloat64Obj()方法将Java Double对象作为ION Float字段写入目标byte数组。这是一个" IonWriter"writeFloat64Obj()
示例:
Double value = new Double(123.123d); writer.writeFloat64Obj(value);
writeFloat64Obj()方法还支持将null写入,在这种情况下,将写入长度为0的ION Float字段(表示一个null浮点字段)。
writeUtf8()
writeUtf8()方法将Java字符串或者UTF-8编码字节的字节数组作为ION UTF-8或者UTF-8-Short字段写入目标字节数组。如果要写入的UTF-8字节中有15个或者更少的字节,则将写入UTF-8-Short字段。否则,将写入UTF-8字段。
这是两个IonWriter``writeUtf8()
的例子:
String value = "Hello"; writer.writeUtf8(value); byte[] valueBytes = "Hello".getBytes("UTF-8") ; writer.writeUtf8(valueBytes);
这两个writeUtf8()方法也都支持将null写入,在这种情况下,将写入长度为0的ION UTF-8字段(代表一个null UTF-8字段)。
如果作为参数传递的"字符串"或者"字节"数组具有0个字符/元素,则将以一个长度为0的长度字节写入UTF-8字段(两个字节共1个前导字节+ 1个长度字节)。这就是将空字符串与null
值区分开的方式。
writeUtc()
writeUtc()方法将Java"日历"作为ION UTC字段写入给定的" byte"数组。这是一个" IonWriter"的writeUtc()示例:
byte[] dest = new byte[10 * 1024]; int destOffset = 0; Calendar value = new GregorianCalendar(); value.setTimeZone(TimeZone.getTimeZone("UTC")); int dateTimeLength = 7; //yyMdhms writer.writeUtc(value, dateTimeLength);
ION UTC字段可以包含使用ION特定字节编码进行编码的日期和时间。编码的长度会有所不同,具体取决于我们要包含的信息量。如果我们看上面的示例,则writeUtc()方法的最后一个参数指定要使用的日期时间格式的"长度"。该示例使用7个字节的长度。在下表中,我们可以看到有效的长度以及它们导致的日期时间格式:
长度 | 描述 |
---|---|
2 | 两个字节,表示介于0到65535之间的年份。没有更多信息。 |
3 | 为长度2,后面添加一个字节,表示一年中的月份(从1到12)。 |
4 | 为长度3,并添加了一个字节,表示一个月中的某天(从1到31)。 |
5 | 在一天中的小时(从0到23)后面加上一个长度为4的字节。 |
6 | 为长度5,并添加了一个代表分钟的字节(从0到59)。 |
7 | 为长度6,并添加了代表秒的字节(引入leap秒时从0到59-60)。 |
9 | 为长度7,并添加了两个字节,代表毫秒(0到999)。 |
10 | 为长度7,并添加了三个字节,表示微秒(0到999,999)。 |
11 | 为长度7,添加了四个字节字节,代表纳秒(0到999,999,999)。 |
关于毫秒,微秒和纳秒,日期时间格式只能包含以下信息之一。我们不能在ION UTC字段中同时发送毫秒,微秒和纳秒(或者其任何组合)。但是,我们可以从纳秒中获取微秒,并可以从微秒中获取毫秒。那应该足够了。
如我们所见,ION UTC字段编码类似于标准的ISO日期时间格式,除了ION UTC编码使用二进制数字(字节)而不是文本数字(字符)来表示日期中的数字。
另外,必须始终以UTC时间发送UTC日期。不允许使用本地日期/时间,因此也没有时区。在任一端都可以轻松地完成与本地日期和时间之间的转换。因此,传递给writeUtc()方法的Calendar
必须在调用writeUtc()
之前的UTC时间。
这种紧凑的编码使ION UTC字段占用了相应ISO日期时间文本格式使用的字节数的大约50%。少了一点,实际上是因为ISO日期时间格式在日期和时间之间具有T字符,并且使用Z或者5个字符对时区进行编码。
除了比ISO日期时间格式更紧凑之外,ION UTC字段还可以更快地进行编码/解码。二进制数字比文本数字的解码速度更快,尤其是当它们由较少的字节组成时。
writeObjectBegin()+ writeObjectEnd()
writeObjectBegin()和writeObjectEnd()方法用于写入ION Object字段的开头和结尾。实际上,ION对象字段没有"结束"标记。 writeObjectEnd()方法实际上跳到ION Object字段的开头并更新其长度字节(在前导字节之后)。
这是一个如何使用writeObjectBegin()和writeObjectEnd()的示例:
byte[] dest = new byte[10 * 1024]; IonWriter writer = new IonWriter(dest, 0); int objectStartIndex = writer.destIndex; int lengthLength = 2; writer.writeObjectBegin(lengthLength); writer.writeKey("field0"); writer.writeInt64(123); writer.writeKey("field1"); writer.writeInt64(456); int objectBodyLength = writer.destIndex - (objectStartIndex + 1 + lengthLength); writer.writeObjectEnd(objectStartIndex, lengthLength, objectBodyLength);
请注意,我们必须如何将lengthLength
参数传递给writeObjectBegin()
。此参数表明要保留多少字节来写入对象的长度。在以后的对writeObjectEnd()的调用中,将对象的长度填充到这些保留的长度字节中。
该示例保留2个字节来表示长度,因为我们知道Object字段主体的长度将永远不会超过2 ^ 16 1(65,535)个字节。实际上,在这种情况下,保留单个长度的字节就足够了,因为"对象"字段的主体长度将不超过255个字节。
还要注意writeKey()
调用。将ION Key字段写入ION Object表示密钥名称或者属性名称。键字段后的ION字段是该键或者属性的值。
writeTableBegin()+ writeTableEnd()
writeTableBegin()和writeTableEnd()方法的工作方式与writeObjectBegin()和writeObjectEnd()方法的工作相似。 writeTableBegin()方法写入ION Table字段的开头,而writeTableEnd()方法跳转并更新Table字段的保留长度字节。
这是一个如何使用writeTableBegin()和writeTableEnd()方法的示例:
byte[] dest = new byte[10 * 1024]; IonWriter writer = new IonWriter(dest, 0); int tableStartIndex = writer.destIndex; int lengthLength = 2; writer.writeTableBegin(lengthLength); writer.writeKey("field0"); writer.writeKey("field1"); writer.writeInt64(123); writer.writeInt64(456); writer.writeInt64(111); writer.writeInt64(222); int tableBodyLength = writer.destIndex - (tableStartIndex + 1 + lengthLength); writer.writeTableEnd(tableStartIndex, lengthLength, tableBodyLength);
注意,我们必须如何将一个lengthLength参数传递给writeTableBegin()。此参数表明要保留多少字节来写入Table字段的长度。在随后的对writeTableEnd()的调用中,表的长度被填充为这些保留的长度字节。
该示例保留2个字节来表示长度,因为我们知道Table字段主体的长度将永远不会超过2 ^ 16 1(65,535)个字节。实际上,在这种情况下,保留单个长度的字节就足够了,因为Table字段主体的长度将不超过255个字节。
还要注意与编写ION Object字段的一个重要区别。 ION Table字段仅包含一次列的键。就像CSV文件的标题行一样。然后,该示例总共写入了4个值字段(2个Int64和2个Float)。这些值字段根据均被写入的顺序与标题相关联。第一个值字段与第一键字段相关,第二个值字段与第二键等
当我们获得的值字段序列号大于"键"字段的数量时,我们将从第一个"键"字段重新开始重新匹配(键索引返回0),然后匹配从该位置继续继续。因此,第三值字段与第一键字段匹配,并且第四值字段与第二键字段匹配。
我们应该确保始终有足够的值字段与键字段的整行匹配。如果表有4个键,则应该有4个值字段的多个(0、4、8、12等)。
注意:我们仍在考虑ION Table字段是否应该包含Table中的行数作为Table中的第一元素,就像Arrays一样。最终可能会是这种情况。如果我们稍作更改,那么上面的代码示例将有所更改。通过查看ION数组的编写方式,我们可以了解有关方法。
writeArrayBegin()+ writeArrayEnd()
静态的writeArrayBegin()和writeArrayEnd()写入ION Array字段的开头和结尾。实际上,ION Array没有"结束"标记。取而代之的是,writeArrayEnd()跳转到数组的开头,并将数组主体的长度(以字节为单位)写入保留的长度字节。
这是有关如何编写ION Array字段的示例:
byte[] dest = new byte[10 * 1024]; IonWriter writer = new IonWriter(dest, 0); int arrayStartIndex = writer.destIndex; int lengthLength = 2; writer.writeArrayBegin(lengthLength); writer.writeInt64(3); //element count writer.writeInt64(456); writer.writeInt64(111); writer.writeInt64(222); int arrayBodyLength = writer.destIndex - (arrayStartIndex + 1 + lengthLength); writer.writeArrayEnd(arrayStartIndex, lengthLength, arrayBodyLength);
请注意,"数组"字段没有键。 ION阵列旨在用于相同类型的ION字段的"匿名"序列。是的,我们实际上可以混合写入ION Array的字段类型,但这不是打算使用ION Array字段的方式。如果我们要使用一系列混合字段类型,请使用ION对象中不包含Key字段(允许)。
还要注意,写入数组的第一个ION字段是如何包含数组中元素数量的Int64-Positive的。对于小于16个元素的数组,还允许使用Tiny字段而不是Int64-Positive字段。
如果我们不知道提前多少个数组中的元素,请保留一定数量的字节以供以后保存数组长度(1个前导字节+ N个字节来保存元素计数)。这类似于稍后将数组的字节长度填充到保留的长度字节中的方式。我们可以始终保留与保留数组的字节长度相同的字节数,因为数组中的元素永远不能超过其内部的字节数(最小的ION字段为1字节长)。
IonWriter静态方法
" IonWriter"的静态方法反映了" IonWriter"的实例方法。以下各节介绍了静态方法。
writeBytes()
静态的writeBytes()方法将原始字节序列(数组)作为Bytes ION字段写入给定的字节数组。这是一个" IonWriter"writeBytes()
示例:
byte[] src = new byte[128]; byte[] dest = new byte[10 * 1024]; int destOffset = 0; int bytesWritten = IonWriter.writeBytes(dest, destOffset, src);
writeBytes()方法返回写入byte数组的字节总数,包括Bytes ION字段的前导字节,长度字节和源数组的原始字节。
writeBoolean()
静态的writeBoolean()方法以给定的偏移量将boolean ION字段(编码为Tiny)写入给定的byte数组。这是一个" IonWriter"的" writeBoolean()"示例:
byte[] dest = new byte[10 * 1024]; int destOffset = 0; int bytesWritten = IonWriter.writeBoolean(dest, destOffset, true);
"布尔"被编码为"微小"离子场。 Tiny字段始终总共占用1个字节。
writeInt64()
静态方法writeInt64()将最长64位的整数写入给定的byte数组。根据给定值是正值还是负值,使用的ION字段将为Int64-Positive或者Int64-Negative。这是一个" IonWriter"writeInt64()
示例:
byte[] dest = new byte[10 * 1024]; int destOffset = 0; int value = 123456; int bytesWritten = IonWriter.writeInt64(dest, destOffset, value);
writeInt64()方法返回写入字节数组的字节总数。 Int64阳性/ Int64阴性ION字段的长度最多为64位(8字节),外加Lead字段的一个额外字节。因此,总共2到9个字节。
writeFloat32()
静态的writeFloat32()方法将32位浮点(Java float)作为ION Float字段写入给定的字节数组。这是一个" IonWriter"的writeFloat32()示例:
byte[] dest = new byte[10 * 1024]; int destOffset = 0; float value = 12.34f; int bytesWritten = IonWriter.writeFloat32(dest, destOffset, value);
Java" float"总是写为ION Float字段,该字段为4字节(32位)加上1个前导字节,表示总共5个字节。
writeFloat64()
静态的writeFloat64()方法将64位浮点(Java double)写入给定的byte数组。这是一个" IonWriter"的writeFloat64()示例:
byte[] dest = new byte[10 * 1024]; int destOffset = 0; double value = 1234.5678d; int bytesWritten = IonWriter.writeFloat64(dest, destOffset, value);
Java" double"总是写为8个字节(64位)加上1个前导字节的ION Float字段,表示总共9个字节。
writeUtf8()
静态的writeUtf8()方法将Java String写入ION UTF-8字段。这是一个" IonWriter"的writeUtf8()示例:
byte[] dest = new byte[10 * 1024]; int destOffset = 0; String value = "A String"; int bytesWritten = IonWriter.writeUtf8(dest, destOffset, value);
" IonWriter"还包含另一个版本的" writeUtf8()",该版本采用"字节"数组作为参数,而不是"字符串"。 " byte"数组中的字节必须已经被编码为UTF-8. writeUtf8()方法不会触及这些字节。它们仅被复制到目标字节数组。以下是使用该writeUtf8()方法的示例:
byte[] dest = new byte[10 * 1024]; int destOffset = 0; byte[] value = "A String".getBytes("UTF-8"); int bytesWritten = IonWriter.writeUtf8(dest, destOffset, value);
在将字符串写入目标byte
数组之前,先将其转换为UTF-8编码的字节。如果UTF-8编码的字节总数不超过15,则将它们写为ION UTF-8-Short字段。如果UTF-8编码的字节总数为16个或者更多,则将它们写为ION UTF-8字段。
writeUtc()
静态的writeUtc()方法将Java日历作为ION UTC字段写入给定的byte数组。这是一个" IonWriter"的writeUtc()示例:
byte[] dest = new byte[10 * 1024]; int destOffset = 0; Calendar value = new GregorianCalendar(); value.setTimeZone(TimeZone.getTimeZone("UTC")); int dateTimeLength = 7; int bytesWritten = IonWriter.writeUtc(dest, destOffset, value, dateTimeLength);
ION UTC字段可以包含使用ION特定字节编码进行编码的日期和时间。编码的长度会有所不同,具体取决于我们要包含的信息量。如果查看上面的示例,则writeUtc()方法的最后一个参数指定要使用的日期时间格式的"长度"。该示例使用7个字节的长度。在下表中,我们可以看到有效的长度以及它们导致的日期时间格式:
长度 | 描述 |
2 | 两个字节,表示介于0到65535之间的年份。没有更多信息。 |
3 | 为长度2,后面添加一个字节,表示一年中的月份(从1到12)。 |
4 | 为长度3,并添加了一个字节,表示一个月中的某天(从1到31)。 |
5 | 在一天中的小时(从0到23)后面加上一个长度为4的字节。 |
6 | 为长度5,并添加了一个代表分钟的字节(从0到59)。 |
7 | 为长度6,并添加了代表秒的字节(引入leap秒时从0到59-60)。 |
9 | 为长度7,并添加了两个字节,代表毫秒(0到999)。 |
10 | 为长度7,并添加了三个字节,表示微秒(0到999,999)。 |
11 | 为长度7,添加了四个字节字节,代表纳秒(0到999,999,999)。 |
关于毫秒,微秒和纳秒,日期时间格式只能包含以下信息之一。我们不能在ION UTC字段中同时发送毫秒,微秒和纳秒(或者其任何组合)。但是,我们可以从纳秒中得出微秒,而可以从微秒中得出毫秒。那应该足够了。
如我们所见,ION UTC字段编码类似于标准的ISO日期时间格式,除了ION UTC编码使用二进制数字(字节)代替文本数字(字符)来表示日期中的数字。
另外,必须始终以UTC时间发送UTC日期。不允许使用本地日期/时间,因此也没有时区。在任一端都可以轻松地完成与本地日期和时间之间的转换。因此,传递给writeUtc()方法的Calendar
必须在UTC时间之前调用writeUtc()
。
这种紧凑的编码使ION UTC字段占用了相应ISO日期时间文本格式使用的字节数的大约50%。少了一点,实际上是因为ISO日期时间格式在日期和时间之间具有T字符,并且使用Z或者5个字符对时区进行编码。
除了比ISO日期时间格式更紧凑之外,ION UTC字段还可以更快地进行编码/解码。二进制数字比文本数字的解码速度更快,尤其是当它们由较少的字节组成时。
编写多个字段
当将多个ION字段依次写入同一字节数组时,我们需要使用最后写入的ION字段之后的第一个字节的索引作为下一个ION字段的起始索引。这是一个Java示例,向我们展示如何执行此操作:
byte[] dest = new byte[10 * 1024]; int destOffset = 0; int index = 0; index += IonWriter.writeInt64 (dest, destOffset, 123456); index += IonWriter.writeFloat32(dest, destOffset, 123.456f); index += IonWriter.writeFloat64(dest, destOffset, 987.654d);
写作复杂领域
复杂ION字段是可以其中包含其他字段的字段。三种最常用的复杂ION字段是"对象","表"和"数组"。实际上,我们也可以将ION字段嵌套在Bytes字段中,因为Bytes字段可以容纳包括ION字段在内的所有原始字节。
所有ION字段在其开头都包含其字节长度。复杂字段的挑战是,我们通常不提前知道嵌套在复杂字段中的字段将占用多少字节。在这种情况下,我们不能在复数字段的开头在其主体中写入字节数。
为了解决这个问题,我们有一个小技巧。我们无需保留其主体占用复数字段开头的字节数,而只是保留足以容纳该长度的字节数。完成将字段写入复杂字段的主体后,我们知道这些字段总计多少字节。然后,我们可以跳回去并将长度写到保留的长度字节中。
我们应该保留多少个长度字节?如果我们知道复杂字段的主体永远不会超过255个字节,请保留1个长度字节。如果正文的长度永远不会超过65,535个字节,则保留2个字节。如果正文的长度永远不会超过16,777,216字节,请保留3个字节,等等。ION字段最多可以包含15个长度的字节,但是我们通常永远不需要超过4个字节。
用于表示ION字段的长度(以字节为单位)的字节数通常称为" lengthLength"。这意味着表示ION字段主体的"长度"(以字节为单位)所需的"长度"(以字节为单位)。如果ION字段的值(正文)长度小于256个字节,则lengthLength为1(字节)就足够了。如果ION字段的值长度小于65,536字节,则lengthLength为2(字节)就足够了,依此类推。
复杂字段的写方法将保留和稍后填充lengthLength字节。
writeObjectBegin()+ writeObjectEnd()
静态的writeObjectBegin()和writeObjectEnd()方法用于写入ION Object字段的开头和结尾。实际上,ION对象字段没有"结束"标记。 writeObjectEnd()方法实际上跳到ION Object字段的开头并更新其长度字节(在前导字节之后)。
这是一个如何使用writeObjectBegin()和writeObjectEnd()的示例:
byte[] dest = new byte[10 * 1024]; int destOffset = 0; int index = 0; int objectStartIndex = index; int lengthLength = 2; index += IonWriter.writeObjectBegin(dest, index, lengthLength); index += IonWriter.writeKey(dest, index, "field0"); index += IonWriter.writeInt64 (dest, destOffset, 123456); index += IonWriter.writeKey(dest, index, "field1"); index += IonWriter.writeFloat32(dest, destOffset, 123.456f); // index - objectStartIndex = full byte length of object int objectFullByteLength = index - objectStartIndex; // Length of the value (body) of an object should not include // the ION field lead byte (1 byte) or the length bytes (lengthLength number of bytes) int objectBodyByteLength = objectFullByteLength - 1 - lengthLength; IonWriter.writeObjectEnd(dest, objectStartIndex, lengthLength, objectBodyByteLength);
请注意,我们必须如何将lengthLength
参数传递给writeObjectBegin()
。此参数表明要保留多少字节来写入对象的长度。在以后的对writeObjectEnd()的调用中,将对象的长度填充到这些保留的长度字节中。
该示例保留2个字节来表示长度,因为我们知道Object字段主体的长度将永远不会超过2 ^ 16 1(65,535)个字节。实际上,在这种情况下,保留单个长度的字节就足够了,因为"对象"字段的主体长度将不超过255个字节。
还要注意writeKey()
的调用。将ION Key字段写入ION Object表示密钥名称或者属性名称。键字段后的ION字段是该键或者属性的值。
writeTableBegin()+ writeTableEnd()
静态的writeTableBegin()和writeTableEnd()方法的工作方式与writeObjectBegin()和writeObjectEnd()方法的工作原理类似。 writeTableBegin()方法写入ION Table字段的开头,而writeTableEnd()方法跳转并更新Table字段的保留长度字节。
这是一个如何使用writeTableBegin()和writeTableEnd()方法的示例:
byte[] dest = new byte[10 * 1024]; int destOffset = 0; int index = 0; int tableStartIndex = index; int lengthLength = 2; index += IonWriter.writeTableBegin(dest, index, lengthLength); index += IonWriter.writeKey(dest, index, "field0"); index += IonWriter.writeKey(dest, index, "field1"); index += IonWriter.writeInt64 (dest, destOffset, 123456); index += IonWriter.writeFloat32(dest, destOffset, 123.456f); index += IonWriter.writeInt64 (dest, destOffset, 123456); index += IonWriter.writeFloat32(dest, destOffset, 123.456f); // index - tableStartIndex = full byte length of Table field int tableFullByteLength = index - tableStartIndex; // Length of the value (body) of an Table should not include // the ION field lead byte (1 byte) or the length bytes (lengthLength number of bytes) int tableBodyByteLength = tableFullByteLength - 1 - lengthLength; IonWriter.writeTableEnd(dest, tableStartIndex, lengthLength, tableBodyByteLength);
注意,我们必须如何将一个lengthLength参数传递给writeTableBegin()。此参数表明要保留多少字节来写入Table字段的长度。在随后的对writeTableEnd()的调用中,表的长度被填充为这些保留的长度字节。
该示例保留2个字节来表示长度,因为我们知道Table字段主体的长度将永远不会超过2 ^ 16 1(65,535)个字节。实际上,在这种情况下,保留单个长度的字节就足够了,因为Table字段主体的长度将不超过255个字节。
还要注意与编写ION Object字段的一个重要区别。 ION Table字段仅包含一次列的键。就像CSV文件的标题行一样。然后,该示例总共写入了4个值字段(2个Int64和2个Float)。这些值字段根据都被写入的顺序与标题相关联。第一值字段与第一键字段相关,第二值字段与第二键等
当我们获得的值字段序列号大于"键"字段的数量时,我们将从第一个"键"字段重新开始重新匹配(键索引返回0),然后匹配从该位置继续继续。因此,第三值字段与第一键字段匹配,并且第四值字段与第二键字段匹配。
我们应该确保始终有足够的值字段与键字段的整行匹配。如果表有4个键,则应该有4个值字段(0、4、8、12等)的倍数。
注意:我们仍在考虑ION Table字段是否应该包含Table中的行数作为Table中的第一元素,就像Arrays一样。最终可能会是这种情况。如果我们稍作更改,那么上面的代码示例将有所更改。通过查看ION数组的编写方式,我们可以了解有关方法。
writeArrayBegin()+ writeArrayEnd()
静态的writeArrayBegin()和writeArrayEnd()写入ION Array字段的开头和结尾。实际上,ION Array没有"结束"标记。取而代之的是,writeArrayEnd()跳转到数组的开头,并将数组主体的长度(以字节为单位)写入保留的长度字节。
这是有关如何编写ION Array字段的示例:
byte[] dest = new byte[10 * 1024]; int destOffset = 0; int index = 0; int arrayStartIndex = index; int lengthLength = 2; index += IonWriter.writeArrayBegin(dest, index, lengthLength); // element count obligatory, and must come before element fields. int arrayElementCount = 3; index += IonWriter.writeInt64 (dest, destOffset, arrayElementCount); // array elements. index += IonWriter.writeInt64 (dest, destOffset, 123); index += IonWriter.writeInt64 (dest, destOffset, 456); index += IonWriter.writeInt64 (dest, destOffset, 789); // index - arrayStartIndex = full byte length of Table field, int arrayFullByteLength = index - arrayStartIndex; // Length of the value (body) of an Array should not include // the ION field lead byte (1 byte) or the length bytes (lengthLength number of bytes) int arrayBodyByteLength = arrayFullByteLength - 1 - lengthLength; IonWriter.writeArrayEnd(dest, arrayStartIndex, lengthLength, arrayBodyByteLength);
请注意,"数组"字段没有键。 ION阵列旨在用于相同类型的ION字段的"匿名"序列。是的,我们实际上可以混合写入ION Array的字段类型,但这不是打算使用ION Array字段的方式。如果我们要使用一系列混合字段类型,请使用ION对象中不包含Key字段(允许)。
还要注意,写入数组的第一个ION字段是如何包含数组中元素数量的Int64-Positive的。对于小于16个元素的数组,还允许使用Tiny字段而不是Int64-Positive字段。
如果我们不知道提前多少个数组中的元素,请保留一定数量的字节以供以后保存数组长度(1个前导字节+ N个字节来保存元素计数)。这类似于稍后将数组的字节长度填充到保留的长度字节中的方式。我们可以始终保留与保留数组的字节长度相同的字节数,因为数组中的元素永远不能超过其内部的字节数(最小的ION字段为1字节长)。