将大量二进制数据加载到原始 JVM 字节码中的“[B”
Loading large amount of binary data into a `[B` in raw JVM bytecode
我正在使用 Krakatau 语法生成 JVM 字节码,以将大型二进制 blob 加载到 [B
中。重点是将所有实际数据存储在 .class
文件中,而不是在运行时从外部源读取它。
我生成的代码如下所示:
.method public static loadImage : ([B)V
.code stack 6 locals 1
aload_0
iconst_0
iconst_1
iadd
dup2
bipush 71
bastore
iconst_1
iadd
dup2
bipush 108
bastore
...
iconst_1
iadd
dup2
bipush 0
bastore
return
.end code
.end method
但是,在运行时此方法失败,因为它太长了:
Exception in thread "main" java.lang.ClassFormatError:
Invalid method Code length 572931 in class file Image
是否有更好的方法将大型二进制 blob 加载到字节数组中?我想一种解决方法是保留我当前的代码,但将其拆分为几个方法,但这非常可怕...
最好的选择可能是将数据存储在与 JAR 一起分发的文件中,并将其加载到该文件中。
如果您确实必须将数据存储在真正为代码设计的 class 文件中,您可以将数据存储在 ISO-8859-1 格式的字符串中并调用 string.getBytes("ISO-8859-1")
在您的 class 上放置一个静态字段,该字段通过读取资源进行静态初始化。我在下面使用 Guava ByteStreams,尽管使用您喜欢的任何 io utils...
class MyClass {
static byte[] theData;
static {
try {
theData = ByteStreams.toByteArray(MyClass.class.getClassLoader().getResourceAsStream('/myBigResource.dat'))
} catch (IOException e) {
throw new RuntimeException(e);
}
}
...
}
您需要在 class 加载时间读取次要资源一次,但即使您将字节数据嵌入到您的 .class 文件中,您仍然会得到它。您获得的唯一真正的额外成本是定位和打开一个额外的资源,加上其中涉及的任何对象交互。
唯一真正的问题是异常处理。如果读取资源抛出一个 IOException,它将作为 ClassNotFound 异常出现在您的程序中,这可能会造成混淆。
您还需要注意,这将在您的 class 路径中搜索资源文件。有人可以将一个 'similarly' 命名的文件放在某处并造成破坏。特别是如果它是一个非常大的文件。
我正在使用 Krakatau 语法生成 JVM 字节码,以将大型二进制 blob 加载到 [B
中。重点是将所有实际数据存储在 .class
文件中,而不是在运行时从外部源读取它。
我生成的代码如下所示:
.method public static loadImage : ([B)V
.code stack 6 locals 1
aload_0
iconst_0
iconst_1
iadd
dup2
bipush 71
bastore
iconst_1
iadd
dup2
bipush 108
bastore
...
iconst_1
iadd
dup2
bipush 0
bastore
return
.end code
.end method
但是,在运行时此方法失败,因为它太长了:
Exception in thread "main" java.lang.ClassFormatError:
Invalid method Code length 572931 in class file Image
是否有更好的方法将大型二进制 blob 加载到字节数组中?我想一种解决方法是保留我当前的代码,但将其拆分为几个方法,但这非常可怕...
最好的选择可能是将数据存储在与 JAR 一起分发的文件中,并将其加载到该文件中。
如果您确实必须将数据存储在真正为代码设计的 class 文件中,您可以将数据存储在 ISO-8859-1 格式的字符串中并调用 string.getBytes("ISO-8859-1")
在您的 class 上放置一个静态字段,该字段通过读取资源进行静态初始化。我在下面使用 Guava ByteStreams,尽管使用您喜欢的任何 io utils...
class MyClass {
static byte[] theData;
static {
try {
theData = ByteStreams.toByteArray(MyClass.class.getClassLoader().getResourceAsStream('/myBigResource.dat'))
} catch (IOException e) {
throw new RuntimeException(e);
}
}
...
}
您需要在 class 加载时间读取次要资源一次,但即使您将字节数据嵌入到您的 .class 文件中,您仍然会得到它。您获得的唯一真正的额外成本是定位和打开一个额外的资源,加上其中涉及的任何对象交互。
唯一真正的问题是异常处理。如果读取资源抛出一个 IOException,它将作为 ClassNotFound 异常出现在您的程序中,这可能会造成混淆。
您还需要注意,这将在您的 class 路径中搜索资源文件。有人可以将一个 'similarly' 命名的文件放在某处并造成破坏。特别是如果它是一个非常大的文件。