您的位置:首页 > 编程语言 > Java开发

Java 结构体之 JavaStruct 使用教程<二> JavaStruct 用例分析

2017-07-21 14:23 519 查看

使用环境

前一篇在介绍 JavaStruct 类时指定了使用库使用环境为 Java 5 及以上,也即开发我们使用的 JDK 版本为1.5及以上就可以了。以下讲解的用例可以直接将 code 直接粘贴到 java 的 main 函数中执行就可以了,后面会给出测试用例和结果。

使用方法

JavaStruct 类用于打包和解包结构体,也即使用方法为用该类的 pack 与 unpack 方法将定义的 struct 类转换为字节流,或者将接收的字节流转换为我们定义的 struct 类。如下所示为一个简单的用于检查结构体类的单元测试方法。结构体成员变量前有一个排序数值,也即注解方式为  @StructField(order = 0) 这是因为 Java JVM 规范没有任何有关类成员排序的说明。使用此方式定义的结构体成员会按照具体实现中使用的order进行成员内存排序,因此每一个结构体成员必须提供一个 order 数值。如下所示: @StructClass
public class Foo {

@StructField(order = 0)
public byte b;

@StructField(order = 1)
public int i;

}注意,注解 @StructClass 以及 @StructField 不能省略。结构体定义完成后,使用 pack 与 unpack 方法进行类型转换,如下所示为完整示例:
public class test {

@StructClass
public class Foo {

@StructField(order = 0)
public byte b;

@StructField(order = 1)
public int i;

}

public void TestFoo() {
try {
// Pack the class as a byte buffer
Foo f = new Foo();
f.b = (byte)1;
f.i = 2;
byte[] b = JavaStruct.pack(f);
for (int i = 0; i < b.length; i++) {
System.out.printf("b[%d]: %d\n", i, b[i]);
}

// Unpack it into an object
Foo f2 = new Foo();
JavaStruct.unpack(f2, b);
System.out.println("f2.b: " + f2.b);
System.out.println("f2.i: " + f2.i);

} catch(StructException e) {
e.printStackTrace();
}
}

public static void main(String args[]) {
test t = new test();
t.TestFoo();
}
}直接观察输出结果:



从输出结果可以看到,我们定义的结构体被转换成了 5 个字节的 byte 数组(int 占 4 个字节),可以看出来 int 数据的地字节保存在了 byte 数组的高地址,可见使用 pack 打包时为大端排序。当然,实际应用时我们需要根据需求决定是使用大端还是小端排序。在 pack 与 unpack 方法指定就可以了,具体 pack 默认为大端还是小端排序和处理器架构及编译器版本都有关系,因此要在项目应用中以真实结果为准。如改成小端:
byte[] b = JavaStruct.pack(f, ByteOrder.LITTLE_ENDIAN); 
如果运行中发生错误,结构体操作会抛出 StructException 异常。
Struct 类也可以直接与 Stream 流一起使用。可以参考 Photoshop ACB 文件读取 example,这里就不作详细分析了。片段如下:
public void TestACB() {
public void read(String acbFile) {
try {
FileInputStream fis = new FileInputStream(new File(acbFile));
header = new ACBHeader();
StructUnpacker up = JavaStruct.getUnpacker(fis, ByteOrder.BIG_ENDIAN);
up.readObject(header);
}
}
}

原型相关

对于使用原型,要注意对于 private 与 protected 成员需要用相应的gettersetter 方法。Transient 成员会被自动排除。如下所示:
@StructClass
public class PublicPrimitives implements Serializable {

@StructField(order = 0)
public byte b;

@StructField(order = 1)
public char c;

@StructField(order = 2)
public short s;

@StructField(order = 3)
public int i;

@StructField(order = 4)
public long lo;

@StructField(order = 5)
protected float f;

@StructField(order = 6)
private double d;

transient int blah;
transient double foo;

public float getF() {
return f;
}

public void setF(float f) {
this.f = f;
}

public double getD() {
return d;
}

public void setD(double d) {
this.d = d;
}

public boolean equals(Object o){
PublicPrimitives other = (PublicPrimitives)o;
return (this.b == other.b
&& this.c == other.c
&& this.s == other.s
&& this.i == other.i
&& this.lo == other.lo
&& this.f == other.f
&& this.d == other.d);
}
}

数组相关

使用数组有一些先决条件。当解包时,数组一定要分配充足的空间。只有那些在另一个字段中使用ArrayLengthMarker(见下文) 定义长度的数组可以为 null,这些数组在解包时会自动分配空间。除此之外的数组定义不能为空和未初始化状态。使用如下所示:
@StructClass
public class PublicPrimitiveArrays {
@StructField(order = 0)
public byte[] b = new byte[5];

@StructField(order = 1)
public char[] c = new char[10];

@StructField(order = 2)
public short[] s;

@StructField(order = 3)
public int[] i;
}

数组长度标记相关

数组长度标记(Array Length Markers)对于长度在另一个字段中定义的字段十分有用。参见以下示例,这是个特殊的字符串结构体,其有一个长度字段以及紧跟其后的对应这个长度的 16 位字符。也即结构为:
| Length | UTF-16 Characters ... |
为了处理这种情况,必须把这些字符串表示为一个特殊的结构体类。长度字段应该注解为“ArrayLengthMarker”。通过这种方式,javastruct 可以在打包及解包操作中操作数组字段时自动使用长度字段中的值。示例如下:
@StructClass
public class AString {

@StructField (order = 0 )
@ArrayLengthMarker (fieldName = "chars")
public int length;

@StructField (order = 1)
public char[] chars;

public AString(String content){
this.length = content.length();
this.chars = content.toCharArray();
}
}
关于 JavaStruct 应用的文章系列,可以移步至如下链接:1. 《Java 结构体之 JavaStruct 使用教程<一> 初识 JavaStruct》2. 《Java 结构体之 JavaStruct 使用教程<二> JavaStruct 用例分析》3. 《Java 结构体之 JavaStruct 使用教程<三> JavaStruct 数组进阶》

下载地址:http://download.csdn.net/download/jazzsoldier/9905451
有任何疑问或使用问题可以给我评论或者邮件哦,觉得有用就点赞吧~:-D
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: