2

我正在以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 加载到字节数组中?我想一种解决方法是保留我当前的代码,但将其拆分为几种方法,但这太可怕了......

4

2 回答 2

3

最好的选择可能是将数据存储在与 JAR 一起分发的文件中,将其加载到该文件中。

如果您确实必须将数据存储在真正为代码设计的类文件中,您可以将数据存储在 ISO-8859-1 格式的字符串中并调用string.getBytes("ISO-8859-1")

于 2016-02-02T12:57:06.903 回答
1

在您的类上放置一个静态字段,该字段通过读取资源进行静态初始化。我在下面使用 Guava ByteStreams,尽管使用任何你喜欢的 io 工具......

class MyClass {
    static byte[] theData; 
    static {
        try { 
            theData = ByteStreams.toByteArray(MyClass.class.getClassLoader().getResourceAsStream('/myBigResource.dat'))
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
     ...
}

您需要在类加载时仅读取一次辅助资源的成本,但即使您的 .class 文件中嵌入了字节数据,您仍然会得到它。您获得的唯一真正的额外成本是找到并打开一个额外的资源,以及其中涉及的任何对象交互。

唯一真正的问题是异常处理。如果读取资源会引发 IOException,该异常将作为 ClassNotFound 异常出现在您的程序中,这可能会造成混淆。

您还需要注意,这将在您的类路径中搜索资源文件。有人可以在某处放置一个“类似”命名的文件并造成严重破坏。特别是如果它是一个非常大的文件。

于 2016-02-02T13:08:30.037 回答