从 ByteBuffer 读取字符串而不使用双缓冲

Posted

技术标签:

【中文标题】从 ByteBuffer 读取字符串而不使用双缓冲【英文标题】:Reading a String from ByteBuffer without double buffering 【发布时间】:2013-02-25 23:49:36 【问题描述】:

有没有办法从ByteBuffer 构造一个String,而无需先从缓冲区读取内容到中间byte[]char[]

类似于string constructor that takes a byte[] 的 API 让我觉得很理想:

public String(ByteBuffer buffer, int offset, int length, Charset charset)

...但不存在这样的东西。

我找到了How to convert from ByteBuffer to Integer and String?,但它使用了一个辅助数组。

到目前为止,我发现的下一个最好的事情是将字节缓冲区投影为CharBuffer 并调用toString()。但这不允许使用 UTF-8 之类的东西来压缩字符串。

【问题讨论】:

你的 ByteBuffer 支持 array() 方法吗? 它是内存映射的,所以我不这么认为。但这些都是我希望我使用的任何 API 都能理解的错综复杂的东西。 我对您要完成的工作感到困惑。您可以使用array 方法获取ByteBuffer 的支持字节数组。除了不想依赖内部实现细节之外,您的最终目标是什么? @Perception,array是可选操作,可以抛出UnsupportedOperationException - If this buffer is not backed by an accessible array。我想如果 ByteBuffer 是一个 1 GB 的内存映射文件,那会发生确切的事情。 字节数组支持ByteBuffers 在所有方面都毫无意义(为什么不直接使用byte[]);因此可以合理地假设一个人可能正在使用本机缓冲区。 【参考方案1】:

CharsetDecoder.decode 和在返回的 CharBuffer 上调用 toString 怎么样。

【讨论】:

【参考方案2】:

没有这样的东西。

ByteBuffer 不包含字符。必须先将它们转换为字符,然后才能将它们制成字符串。

此外,字符串必须在 JVM 内存中。 ByteBuffer 可以是映射的,也可以是直接的,在这两种情况下它都在 JVM 之外。

为了将数据移动到 JVM 并将其转换为字符,您必须使用辅助数组。

【讨论】:

是的,但我不明白为什么 String 不能在构造函数中做到这一点。为什么要在旨在实现高性能的 API 中强制使用额外的数组副本? 不会有任何性能优势,只会增加已经相当复杂的 API 的复杂性。【参考方案3】:

java.lang.String 是不可变的和最终的,因此最终别无选择,只能最终以它已经接受的格式提供数据。 (当然没有通过反射来操纵它的内部......)

您可以隐藏使用字符串构建器或其他东西的 API 背后的丑陋,但在某些时候,内存中会存在数组的两个副本,一个在构建器中,另一个用于实际字符串。

【讨论】:

例如在 Sun JDK 1.6.0_u34 中,java.lang.String 有一个包私有构造函数如下:/* Package private constructor which shares value array for speed. */ String(int offset, int count, char value[]) ... 在我看来java.lang 中的 API 可以避免第二个数组... 是的,所以如果您使用反射来覆盖对该构造函数的访问,您可以这样做,正如我所提到的 :) 哈哈,点头。反射会破坏这里的目的。但是包私有意味着同一个包中的其他类可以使用构造函数而无需任何愚蠢。此 API 似乎已明确保留以进行优化。我希望他们能利用他们所获得的凉爽...... 好吧,如果实际问题只是“Sun 为什么不做 XYZ?”除非一位前 Sun 工程师碰巧正在阅读,否则我们无法真正为您提供权威答案.... :)【参考方案4】:

Stringchars 组成,而不是 bytes。您需要一个字符集,用于将字节转换为字符,例如UTF-8、UTF-16、ISO-8859-1、ISO-8859-5、...

如果你不知道字符集,你就不会知道字节代表哪个字符

【讨论】:

我同意。但这就是为什么我梦想的 API 需要一个字符集......请参阅我的 OP。

以上是关于从 ByteBuffer 读取字符串而不使用双缓冲的主要内容,如果未能解决你的问题,请参考以下文章

玩转 ByteBuffer

Java NIO ByteBuffer:在读取完整消息之前先读取消息大小

从 tun 设备读取()而不删除从操作系统缓冲区读取的数据

从长度为无符号整数的 ByteBuffer 中读取 UTF-8 字符串

在 JNA 调用中使用 ByteBuffer 表示字符串会导致缓冲区中出现额外字符

Java Bytebuffer 只能顺序读取?