IonReader

时间:2020-01-09 10:35:44  来源:igfitidea点击:

" 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的各种方法时,将设置公共变量。公用变量是:

变量描述
sourcebyte数组
index然后是当前字段的body </ i>的索引(主体,而不是前导字节)。
nextIndex下一个字段的前导字节</ i>的索引。
fieldType当前字段的ION字段类型。该值将匹配
IonFieldTypes
fieldLengthLength当前字段的长度-长度(用于表示字段长度的字节数)。
如果当前字段使用短编码,则fieldLengthLengthfieldLength
将具有相同的值。
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();
}