Java ByteBuffer 清除数据
Java ByteBuffer clear data
我知道 Java 的 ByteBuffer.clear() 并不是真的要清理 ByteBuffer 中的所有数据,所以当我 StringBuilder.append () string 每次,最后的结果总是追加 ByteBuffer 中所有剩余的字符,这些字符是上次写入的旧数据,那么如何解决这个问题?
int byteRead = -1;
int readCount = 0;
int BUFFER_SIZE = 256;
StringBuilder sb = new StringBuilder();
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
ReadableByteChannel readableByteChannel = Channels.newChannel(is);
while ((byteRead = readableByteChannel.read(buffer)) > 0 && readCount < 68) {
sb.append(new String(buffer.array(), "UTF-8"));
buffer.clear();
readCount++;
}
使用position()
获取当前缓冲区位置,使用Arrays.copyOf
获取部分数组:
Arrays.copyOf(buffer.array(), 0, buffer.position());
你的情况会变成:
sb.append(new String(Arrays.copyOf(buffer.array(), 0, buffer.position()), "UTF-8"));
或者在使用适当的 String 构造函数时甚至更短:
sb.append(new String(buffer.array(), 0, buffer.position(), "UTF-8"));
或者可能是您使用 slice()
寻找的内容:
sb.append(新字符串(buffer.slice().array(), "UTF-8"));
顺便说一句。而不是 "UTF-8"
最好使用 StandardCharsets.UTF_8
.
您可以使用 new String(byte[] bytes, int offset, int length, String charsetName()) 构造函数。
new String(buffer.array(), 0, byteRead, "UTF-8");
这将防止在创建新 String
时使用以前的数据。
正如其他答案已经指出的那样,您必须考虑缓冲区的位置,它由 read
方法更新。所以正确的代码看起来像:
while ((byteRead = readableByteChannel.read(buffer)) > 0 && readCount < 68) {
sb.append(new String(buffer.array(),
buffer.arrayOffset(), buffer.arrayOffset()+buffer.position(), "UTF-8"));
buffer.clear();
readCount++;
}
请注意,在您的特殊情况下,arrayOffset()
将始终为零,但您最好以某种方式编写代码,当您更改缓冲区分配代码时它不会中断。
但是这段代码被破坏了。当您读取多字节 UTF-8 序列时,可能会发生这种情况,该序列的第一个字节在一个操作中被读取,而其余字节在下一个操作中被读取。您尝试从这些不完整的序列创建 String
个实例将产生无效字符。除此之外,你正在创建这些 String
个实例,只是为了将它们的内容复制到一个 StringBuilder
,这是非常低效的。
因此,要正确执行此操作,您应该执行以下操作:
int readCount = 0;
int BUFFER_SIZE = 256;
StringBuilder sb = new StringBuilder();
CharsetDecoder dec=StandardCharsets.UTF_8.newDecoder();
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
CharBuffer cBuffer= CharBuffer.allocate(BUFFER_SIZE);
ReadableByteChannel readableByteChannel = Channels.newChannel(is);
while(readableByteChannel.read(buffer) > 0 && readCount < 68) {
buffer.flip();
while(dec.decode(buffer, cBuffer, false).isOverflow()) {
cBuffer.flip();
sb.append(cBuffer);
cBuffer.clear();
}
buffer.compact();
readCount++;
}
buffer.flip();
for(boolean more=true; more; ) {
more=dec.decode(buffer, cBuffer, true).isOverflow();
cBuffer.flip();
sb.append(cBuffer);
cBuffer.clear();
}
请注意,ReadableByteChannel
和 CharsetDecoder
如何使用它们的位置和限制来处理缓冲区。您所要做的就是正确使用 flip
和 compact
作为 shown in the documentation of compact
.
唯一的例外是附加到 Stringbuilder
,因为那不是 NIO 函数。在那里,我们必须使用 clear()
,因为我们知道 Stringbuilder.append
操作会消耗缓冲区中的所有字符。
请注意,此代码仍然无法处理某些(不可避免的)错误情况,因为您在任意数量的 read
之后停止,所以您总是有可能在多字节的中间切入UTF-8 序列。
但是这个相当复杂的逻辑已经由 JRE 实现了,如果你放弃在一定数量的 bytes 之后切割的想法,你可以利用它:
int readCount = 0;
int BUFFER_SIZE = 256;
StringBuilder sb = new StringBuilder();
CharBuffer cBuffer= CharBuffer.allocate(BUFFER_SIZE);
ReadableByteChannel readableByteChannel = Channels.newChannel(is);
Reader reader=Channels.newReader(readableByteChannel, "UTF-8");
while(reader.read(cBuffer) > 0 && readCount < 68) {
cBuffer.flip();
sb.append(cBuffer);
cBuffer.clear();
readCount++;
}
现在这段代码会将读取限制为 256 × 68
个字符 而不是字节,但是对于 UTF-8
编码的数据,这只有在存在时才会有所不同是多字节序列,您以前显然不关心它。
最后,既然你显然首先有一个 InputStream
,你根本不需要 ReadableByteChannel
绕行:
int readCount = 0;
int BUFFER_SIZE = 256;
StringBuilder sb = new StringBuilder();
CharBuffer cBuffer = CharBuffer.allocate(BUFFER_SIZE);
Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8);
while(reader.read(cBuffer) > 0 && readCount < 68) {
cBuffer.flip();
sb.append(cBuffer);
cBuffer.clear();
readCount++;
}
这可能看起来“不是 NIO 代码”,但是 Reader
s 仍然是读取字符数据的规范方式,即使使用 NIO;没有替代品。 method Reader.read(CharBuffer)
在 NIO 的第一个版本中缺失,但是用 Java 5.
提交了
我知道 Java 的 ByteBuffer.clear() 并不是真的要清理 ByteBuffer 中的所有数据,所以当我 StringBuilder.append () string 每次,最后的结果总是追加 ByteBuffer 中所有剩余的字符,这些字符是上次写入的旧数据,那么如何解决这个问题?
int byteRead = -1;
int readCount = 0;
int BUFFER_SIZE = 256;
StringBuilder sb = new StringBuilder();
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
ReadableByteChannel readableByteChannel = Channels.newChannel(is);
while ((byteRead = readableByteChannel.read(buffer)) > 0 && readCount < 68) {
sb.append(new String(buffer.array(), "UTF-8"));
buffer.clear();
readCount++;
}
使用position()
获取当前缓冲区位置,使用Arrays.copyOf
获取部分数组:
Arrays.copyOf(buffer.array(), 0, buffer.position());
你的情况会变成:
sb.append(new String(Arrays.copyOf(buffer.array(), 0, buffer.position()), "UTF-8"));
或者在使用适当的 String 构造函数时甚至更短:
sb.append(new String(buffer.array(), 0, buffer.position(), "UTF-8"));
或者可能是您使用 slice()
寻找的内容:
sb.append(新字符串(buffer.slice().array(), "UTF-8"));
顺便说一句。而不是 "UTF-8"
最好使用 StandardCharsets.UTF_8
.
您可以使用 new String(byte[] bytes, int offset, int length, String charsetName()) 构造函数。
new String(buffer.array(), 0, byteRead, "UTF-8");
这将防止在创建新 String
时使用以前的数据。
正如其他答案已经指出的那样,您必须考虑缓冲区的位置,它由 read
方法更新。所以正确的代码看起来像:
while ((byteRead = readableByteChannel.read(buffer)) > 0 && readCount < 68) {
sb.append(new String(buffer.array(),
buffer.arrayOffset(), buffer.arrayOffset()+buffer.position(), "UTF-8"));
buffer.clear();
readCount++;
}
请注意,在您的特殊情况下,arrayOffset()
将始终为零,但您最好以某种方式编写代码,当您更改缓冲区分配代码时它不会中断。
但是这段代码被破坏了。当您读取多字节 UTF-8 序列时,可能会发生这种情况,该序列的第一个字节在一个操作中被读取,而其余字节在下一个操作中被读取。您尝试从这些不完整的序列创建 String
个实例将产生无效字符。除此之外,你正在创建这些 String
个实例,只是为了将它们的内容复制到一个 StringBuilder
,这是非常低效的。
因此,要正确执行此操作,您应该执行以下操作:
int readCount = 0;
int BUFFER_SIZE = 256;
StringBuilder sb = new StringBuilder();
CharsetDecoder dec=StandardCharsets.UTF_8.newDecoder();
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
CharBuffer cBuffer= CharBuffer.allocate(BUFFER_SIZE);
ReadableByteChannel readableByteChannel = Channels.newChannel(is);
while(readableByteChannel.read(buffer) > 0 && readCount < 68) {
buffer.flip();
while(dec.decode(buffer, cBuffer, false).isOverflow()) {
cBuffer.flip();
sb.append(cBuffer);
cBuffer.clear();
}
buffer.compact();
readCount++;
}
buffer.flip();
for(boolean more=true; more; ) {
more=dec.decode(buffer, cBuffer, true).isOverflow();
cBuffer.flip();
sb.append(cBuffer);
cBuffer.clear();
}
请注意,ReadableByteChannel
和 CharsetDecoder
如何使用它们的位置和限制来处理缓冲区。您所要做的就是正确使用 flip
和 compact
作为 shown in the documentation of compact
.
唯一的例外是附加到 Stringbuilder
,因为那不是 NIO 函数。在那里,我们必须使用 clear()
,因为我们知道 Stringbuilder.append
操作会消耗缓冲区中的所有字符。
请注意,此代码仍然无法处理某些(不可避免的)错误情况,因为您在任意数量的 read
之后停止,所以您总是有可能在多字节的中间切入UTF-8 序列。
但是这个相当复杂的逻辑已经由 JRE 实现了,如果你放弃在一定数量的 bytes 之后切割的想法,你可以利用它:
int readCount = 0;
int BUFFER_SIZE = 256;
StringBuilder sb = new StringBuilder();
CharBuffer cBuffer= CharBuffer.allocate(BUFFER_SIZE);
ReadableByteChannel readableByteChannel = Channels.newChannel(is);
Reader reader=Channels.newReader(readableByteChannel, "UTF-8");
while(reader.read(cBuffer) > 0 && readCount < 68) {
cBuffer.flip();
sb.append(cBuffer);
cBuffer.clear();
readCount++;
}
现在这段代码会将读取限制为 256 × 68
个字符 而不是字节,但是对于 UTF-8
编码的数据,这只有在存在时才会有所不同是多字节序列,您以前显然不关心它。
最后,既然你显然首先有一个 InputStream
,你根本不需要 ReadableByteChannel
绕行:
int readCount = 0;
int BUFFER_SIZE = 256;
StringBuilder sb = new StringBuilder();
CharBuffer cBuffer = CharBuffer.allocate(BUFFER_SIZE);
Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8);
while(reader.read(cBuffer) > 0 && readCount < 68) {
cBuffer.flip();
sb.append(cBuffer);
cBuffer.clear();
readCount++;
}
这可能看起来“不是 NIO 代码”,但是 Reader
s 仍然是读取字符数据的规范方式,即使使用 NIO;没有替代品。 method Reader.read(CharBuffer)
在 NIO 的第一个版本中缺失,但是用 Java 5.