IonReader
" IonReader"类(" com.nanosai.gridops.ion.read.IonReader")能够迭代存储在" byte"数组中的二进制ION数据。 " IonReader"没有一组静态的API。仅实例方法。本教程将介绍如何使用" IonReader"来读取基本和复杂的ION字段。
创建一个IonReader
在使用" IonReader"之前,我们必须创建一个" IonReader"实例并将其添加到源" byte"数组。这是显示如何创建" IonReader"的示例:
byte[] src = new byte[10 * 1024]; int ionDataLength = 0; // write ION data into src byte array // and set ionDataLength to length of ION data. IonReader reader = new IonReader(src, 0, ionDataLength);
我们还可以创建一个" IonReader"并将其添加到一个" byte"数组中。看起来是这样的:
IonReader reader = new IonReader(); byte[] src = new byte[10 * 1024]; int ionDataLength = 0; // write ION data into src byte array // and set ionDataLength to length of ION data. reader.setSource(src, 0, ionDataLength);
迭代离子场
一旦创建了" IonReader",我们就可以遍历添加的" byte"数组中的ION字段。 " IonReader"具有一种名为" hasNext()"的方法,只要在添加的" byte"数组中有更多数据要读取,该方法就会返回" true"。因此,我们可以像这样迭代"字节"数组中的ION字段:
IonReader reader = new IonReader(); // attach IonReader to a byte array with ION fields here... reader.setSource(src, 0, ionDataLength); while(reader.hasNext()) { reader.next(); reader.parse(); //read the value of each ION field. }
如我们所见,使用IonReader
进行迭代与使用JavaIterator
进行迭代非常相似。
" hasNext()"方法将查找" IonReader"构造函数或者" setSource()"中提供的" ionDataLength",以确定" byte"数组中是否还有更多的ION字段。因此,正确提供ION字段数据的长度(以字节为单位)非常重要。
如果有的话,next()
方法会将IonReader
移动到下一个ION字段。实际上,它只是将内部读取指针移动到当前ION字段之后的第一个字节。
在调用setSource()之后立即调用next()会将内部指针移至字节数组中的第一个ION字段。在第一个next()
调用之前,内部指针指向第一个ION字段"之前"。
parse()方法在源字节数组中解析IonReader当前指向的ION字段。解析字段时,字段类型,长度和长度都存储在" IonReader"的公共变量中,我们可以读取该公共变量以处理ION字段。
我们到底要在while循环中执行什么操作,取决于我们在byte数组中拥有的ION数据类型。如果我们有一系列日志条目,那么我们将遍历每个字段并分别进行处理。如果我们有ION对象,则可能需要解析到该对象并读取其嵌套字段,对象等。在本教程后面的部分中,我们将看到如何做到这一点。
公共变量
" IonReader"具有一组公共变量,可用于在迭代过程中检查或者处理ION字段。变量是公共变量,因此我们可以轻松访问它们,但在写入变量时应格外小心。它们主要用于阅读,不需要使用吸气剂方法。
当我们调用IonReader
的各种方法时,将设置公共变量。公用变量是:
变量 | 描述 |
source | 源byte 数组 |
index | 然后是当前字段的body </ i>的索引(主体,而不是前导字节)。 |
nextIndex | 下一个字段的前导字节</ i>的索引。 |
fieldType | 当前字段的ION字段类型。该值将匹配IonFieldTypes |
fieldLengthLength | 当前字段的长度-长度(用于表示字段长度的字节数)。 如果当前字段使用短编码,则 fieldLengthLength 和fieldLength 将具有相同的值。 |
fieldLength | 当前字段的主体(值)的长度(以字节为单位)。 |
读取原始离子场
用" IonReader"读取原始的ION字段非常简单。当" IonReader"位于原始ION字段时,请调用相应的原始ION字段reader方法。以下各节介绍了原始的ION字段读取方法。
readBoolean()
readBoolean()方法将当前ION字段的值读取为boolean值。 ION字段必须是ION Tiny字段,其值为1(真)或者2(假)(0表示"空")。这是一个" IonReader"," readBoolean()"示例:
boolean value = reader.readBoolean();
readInt64()
readInt64()方法将当前ION字段的值读取为long值。 ION字段必须是ION Int64-Positive>或者Int64-Negative字段。这是一个" IonReader"readInt64()
示例:
long value = reader.readInt64();
readFloat32()
readFloat32()方法将当前ION字段的值读入Java的float值中。 ION字段必须是长度为4(表示长度为4个字节)的ION Float。这是一个IonReader``readFloat32()
示例:
float value = reader.readFloat32();
readFloat64()
readFloat64()方法将当前ION字段的值读取为Java double值。 ION字段必须是长度为8(表示8个字节的长度)的ION Float。这是一个IonReader``readFloat64()
示例:
double value = reader.readFloat64();
readUtf8String()
readUtf8String()方法将当前ION字段的值读入Java String中。 ION字段必须是ION UTF-8或者UTF-8-Short字段。这是一个" IonReader"," readUtf8String()"示例:
String value = reader.readUtf8String();
readUtcCalendar()
readUtcCalendar()
方法将当前ION字段的值读入JavaCalendar
对象。 ION字段必须是ION UTC字段。这是一个" IonReader"," readUtcCalendar()"示例:
Calendar value = reader.readUtcCalendar();
任意层次导航
读取诸如对象,表和数组字段之类的复杂ION字段比仅读取原始类型的ION字段要复杂一些。但是,一旦了解了如何控制这种任意的分层导航,我们就会发现它是导航ION数据的一种非常强大的方法。它使我们可以完全控制要导航的层次结构,并可以轻松快捷地跳过我们不感兴趣的部分。
当我们遍历源"字节"数组中的ION数据时,通常会从一个ION对象,表或者数组直接迭代到同一级别的下一个ION字段(上一个ION字段的下一个"兄弟",因此说话)。
为了读取嵌套在ION Object,Table或者Array字段中的ION字段,我们必须指示" IonReader"解析为复杂的ION字段。我们可以通过调用parseInto()
来实现。
一旦调用了" parseInto()"," IonReader"将迭代嵌套在该ION字段内的ION字段。因此," IonReader"的" hasNext()"方法会更改其语义,以判断ION字段是否具有更多的嵌套元素。因此,我们仍然可以使用while(reader.hasNext())循环来迭代复杂ION字段的嵌套字段。
到达复杂ION字段(对象,表或者数组)的末尾后,我们需要调用parseOutOf()
以退出复杂ION字段。调用parseOutOf()返回IonReader到我们刚刚解析成的ION字段。因此,调用parseInto()将再次跳入相同的ION字段。要进入下一个ION字段,请调用next()
。
这是一个简化的任意层次导航示例:
while(reader.hasNext()) { reader.parse(); if(reader.fieldType == IonFieldTypes.OBJECT) { reader.moveInto(); while(reader.hasNext()) { reader.next(); reader.parse(); //read nested ION field } reader.moveOutOf(); } reader.next(); }
此示例显示了两个层次结构级别的导航。有一个由ION Object字段流组成的外部级别。并且,有一个内部层由嵌套在这些ION Object字段内的字段组成。
实际上,嵌套级别可能会高于2. 例如,如果上述代码的内部嵌套部分(读取ION对象的部分),
读取对象
与读取基本字段相比,使用" IonReader"读取ION对象需要更多的代码。 ION对象通常由ION Key字段+另一个ION字段对组成(尽管并非严格要求)。首先,我们必须阅读Key字段,然后我们需要确定要设置的Java对象中的哪个字段。这是使用IonReader
读取ION对象的示例:
while(reader.hasNext()) { reader.parse(); List<Employee> employees = new ArrayList<>(); if(reader.fieldType == IonFieldTypes.OBJECT) { reader.moveInto(); Employee employee = new Employee(); while(reader.hasNext()) { reader.next(); reader.parse(); // Read property key (name) String key = null; if(reader.fieldType == IonFieldTypes.KEY) { key = reader.reader.readKeyAsUtf8String(); } else if(reader.fieldType == IonFieldTypes.KEY_SHORT) { key = reader.readKeyShortAsUtf8String() } // Read property value reader.next(); reader.parse(); if("firstName".equals(key)){ employee.setFirstName(reader.readUtf8String()); } else if("lastName".equals(key)){ employee.setLastName(reader.readUtf8String()); } else if("employeeId".equals(key)) { employee.setEmployeeId(reader.readInt64()); } } employees.add(employee); reader.moveOutOf(); } reader.next(); }
如我们所见,属性名称(ION键字段)与Java对象中相应属性的匹配当前需要一系列" if else if"语句。这对于具有较少属性的对象来说还可以,但是当属性数量增加时,遍历此" if else if"语句列表会变得越来越慢,因为有更多的" if"语句要测试。
我们目前正在研究使用" IonReader"提高阅读对象的可读性和速度的方法。至少还有其他两种方式可以更快地完成此任务。这些方法准备就绪后,我们将更新本教程。
读取表
使用" IonReader"读取ION Table也需要一些代码,但是也有可能。请记住,ION Tables首先是一系列ION Key字段,然后是一系列根据其索引与Key字段相关联的ION字段。这是一个使用IonReader
读取ION Tables的例子:
while(reader.hasNext()) { reader.parse(); if(reader.fieldType == IonFieldTypes.TABLE) { reader.moveInto(); List<Employee> employees = new ArrayList<>(); // First, parse keys into a list of String List<String> keys = new ArrayList<>(); reader.next(); reader.parse(); while(reader.fieldType == IonFieldTypes.KEY || reader.fieldType == IonFieldTypes.KEY_SHORT) { keys.add(reader.readKeyAsUtf8String()); if(reader.hasNext()) { reader.next(); reader.parse(); } } //Second, read the field values and turn them into Java objects int fieldIndex = 0; Employee employee = null; while(reader.hasNext()) { if(fieldIndex == 0) { employee = new Employee(); employees.add(employee); } String key = keys.get(fieldIndex); if("firstName".equals(key)){ employee.setFirstName(reader.readUtf8String()); } else if("lastName".equals(key)){ employee.setLastName(reader.readUtf8String()); } else if("employeeId".equals(key)) { employee.setEmployeeId(reader.readInt64()); } fieldIndex++; if(fieldIndex == keys.size()) { fieldIndex = 0; } if(reader.hasNext()) { reader.next(); reader.parse(); } } reader.moveOutOf(); } reader.next(); }
该代码比读取ION对象的代码长。但是,一旦代码开始解析ION值字段(在ION Table的开头解析了ION Key字段之后),就会根据读取的value字段的索引查找Key字段。这比必须为表中每个对象(行)的每个属性解析一个Key字段要快。
读取数组
我们也可以使用" IonReader"读取ION Array字段。读取ION数组比读取对象和表更简单。这是使用IonReader
读取ION阵列的示例:
while(reader.hasNext()) { reader.parse(); if(reader.fieldType == IonFieldTypes.ARRAY) { reader.moveInto(); reader.next(); reader.parse(); //first read element count int elementCount = reader.readInt64(); String[] elements = new String[elementCount]; int index = 0; while(reader.hasNext()) { reader.next(); reader.parse(); elements[index] = reader.readUtf8AsString(); } reader.moveOutOf(); } reader.next(); }