从ByteBuffer读取UTF-8字符串,其中length是unsigned int

时间:2009-03-08 20:07:47

标签: java string utf-8 bytebuffer

我试图通过java.nio.ByteBuffer读取UTF8字符串。大小是一个unsinged int,当然,Java没有。我把这个值读成了很长的一段,以便我有了价值。

我的下一个问题是我无法使用long创建一个字节数组,并且将其长时间转换为int会导致它被签名。

我也试过在缓冲区上使用limit(),但是再次使用int不长。

我正在做的具体事情是从类文件中读取UTF8字符串,因此缓冲区中有更多只是UTF8字符串。

有关如何从ByteBuffer读取具有无符号整数int的UTF8字符串的任何想法。

编辑:

Here is an example of the issue

SourceDebugExtension_attribute {
       u2 attribute_name_index;
       u4 attribute_length;
       u1 debug_extension[attribute_length];
    }

attribute_name_index
    The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing the string "SourceDebugExtension".

attribute_length
    The value of the attribute_length item indicates the length of the attribute, excluding the initial six bytes. The value of the attribute_length item is thus the number of bytes in the debug_extension[] item.

debug_extension[]
    The debug_extension array holds a string, which must be in UTF-8 format. There is no terminating zero byte.

    The string in the debug_extension item will be interpreted as extended debugging information. The content of this string has no semantic effect on the Java Virtual Machine.

因此,从技术角度来看,类文件中的字符串可能是完整的u4(无符号,4字节)长度。

如果对UTF8字符串的大小有限制,这些不会成为问题(我不是UTF8专家,所以可能存在这样的限制)。

我可以对它进行试探,并且考虑到不会有长篇字符串的现实......

4 个答案:

答案 0 :(得分:6)

除非您的字节数组超过2GB(Java int的最大正值),否则将long转换回签名int不会有问题}。

如果您的字节数组长度需要超过2GB,那么您做错了,尤其是因为这比JVM的默认最大堆大小更多......

答案 1 :(得分:1)

签署int不会是你的主要问题。假设你有一个长度为40亿的字符串。你需要一个至少为4 GB的ByteBuffer,一个至少为4 GB的byte []。将此转换为String时,至少需要8 GB(每个字符2个字节)和一个StringBuilder来构建它。 (至少8 GB) 所有你需要的,24 GB处理1字符串。即使你有很多记忆,你也不会得到这么大的字符串。

另一种方法是将长度视为已签名,如果未签名则视为错误,因为在任何情况下您都没有足够的内存来处理String。即使要处理长度为20亿(2 ^ 31-1)的字符串,您也需要12 GB才能将其转换为字符串。

答案 2 :(得分:1)

Java数组使用(Java,即signed)int进行访问as per the languge spec,因此不可能有一个字符串(由char数组支持)比Integer.MAX_INT

更长

但即使这样做太多了,无法在一个块中进行处理 - 如果遇到足够大的String,它会完全破坏性能并使程序在大多数机器上出现OutOfMemoryError失败。

你应该做的是处理任何合理大小的字符串,一次说几个megs。那么你可以处理的大小没有实际限制。

答案 3 :(得分:0)

我猜你可以在ByteBuffer之上实现CharSequence。这将允许你保持你的“字符串”不会出现在堆上,尽管大多数处理字符的实用程序实际上都期望一个字符串。即便如此,CharSequence实际上也有限制。它希望将大小作为int返回。

(理论上你可以创建一个新版本的CharSequence,它返回大小的长度,但是Java中没有任何东西可以帮助你处理CharSequence。也许如果你实现{{3}会很有用返回一个普通的CharSequence。)