我一直在试图理解Java是如何工作的。我的目标是将字符串写入ByteBuffer并将其读回。我想了解ByteBuffer属性(如Limit, Capacity, Remaining, Position )是如何由于读写操作而受到影响的。
下面是我的测试程序(为了简洁起见删除了导入语句)。
public class TestBuffer {
private ByteBuffer bytes;
private String testStr = "Stackoverflow is a great place to discuss tech stuff!";
public TestBuffer() {
bytes = ByteBuffer.allocate(1000);
System.out.println("init: " + printBuffer());
}
public static void main(String a[]) {
TestBuffer buf = new TestBuffer();
try {
buf.writeBuffer();
} catch (IOException e) {
e.printStackTrace();
}
buf.readBuffer();
}
// write testStr to buffer
private void writeBuffer() throws IOException {
byte[] b = testStr.getBytes();
BufferedInputStream in = new BufferedInputStream(new ByteArrayInputStream(b));
in.read(bytes.array());
in.close();
System.out.println("write: " + printBuffer());
}
// read buffer data back to byte array and print
private void readBuffer() {
bytes.flip();
byte[] b = new byte[bytes.position()];
bytes.position(0);
bytes.get(b);
System.out.println("data read: " + new String(b));
System.out.println("read: " + printBuffer());
}
public String printBuffer() {
return "ByteBuffer [limit=" + bytes.limit() + ", capacity=" + bytes.capacity() + ", position="
+ bytes.position() + ", remaining=" + bytes.remaining() + "]";
}}
输出
init: ByteBuffer [limit=1000, capacity=1000, position=0, remaining=1000]
write: ByteBuffer [limit=1000, capacity=1000, position=0, remaining=1000]
data read:
read: ByteBuffer [limit=0, capacity=1000, position=0, remaining=0]正如您所看到的,在调用readBuffer()之后没有数据,如果在写和读操作后不同字段的值也没有变化。
更新
下面是我最初试图理解的来自Android屏幕库的工作代码
// retrieve the screenshot
// (this method - via ByteBuffer - seems to be the fastest)
ByteBuffer bytes = ByteBuffer.allocate (ss.width * ss.height * ss.bpp / 8);
is = new BufferedInputStream(is); // buffering is very important apparently
is.read(bytes.array()); // reading all at once for speed
bytes.position(0); // reset position to the beginning of ByteBuffer请帮助我理解这一点。
谢谢
发布于 2015-07-31 14:52:02
你的缓冲区从来没有被填满过。bytes.array()只是检索支持字节数组。如果对此写入任何内容,则ByteBuffer字段(当然除了数组本身)不受影响。所以这个位置保持在零。
您在in.read(bytes.array())中所做的工作与byte[] tmp = bytes.array()和in.read(tmp)相同。对tmp变量的更改不能反映在bytes实例中。支持数组被更改,这可能意味着ByteBuffer的内容也会发生变化。但是支持字节数组中的偏移--包括位置和限制--不是。
您应该只使用任何ByteBuffer方法(不接受索引)来填充put,比如put(byte[])。
我将提供一个代码片段,可以让您思考如何处理字符串、编码、字符和字节缓冲区:
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.StandardCharsets;
public class TestBuffer {
private static final String testStr = "Stackoverflow is a great place to discuss tech stuff!";
private static final boolean END_OF_INPUT = true;
private ByteBuffer bytes = ByteBuffer.allocate(1000);
public TestBuffer() {
System.out.println("init : " + bytes.toString());
}
public static void main(String a[]) {
TestBuffer buf = new TestBuffer();
buf.writeBuffer();
buf.readBuffer();
}
// write testStr to buffer
private void writeBuffer() {
CharBuffer testBuffer = CharBuffer.wrap(testStr);
CharsetEncoder utf8Encoder = StandardCharsets.UTF_8.newEncoder();
CoderResult result = utf8Encoder.encode(testBuffer, bytes, END_OF_INPUT);
if (result.isError()) {
bytes.clear();
throw new IllegalArgumentException("That didn't go right because " + result.toString());
}
if (result.isOverflow()) {
bytes.clear();
throw new IllegalArgumentException("Well, too little buffer space.");
}
System.out.println("written: " + bytes.toString());
bytes.flip();
}
// read buffer data back to byte array and print
private void readBuffer() {
byte[] b = new byte[bytes.remaining()];
bytes.get(b);
System.out.println("data : " + new String(b, StandardCharsets.UTF_8));
System.out.println("read : " + bytes.toString());
bytes.clear();
}
}请注意,缓冲区和流实际上是处理顺序数据的两种不同方式。如果你试图同时使用这两种方法,你可能会试图变得太聪明。
您也可以在不使用CharBuffer和ByteBuffer的情况下使用byte[]缓冲区和由ReaderInputStream包装的StringReader来解决这个问题。
安卓的代码完全滥用了ByteBuffer。它应该创建一个byte[]并将其包装起来,从而设置容量的限制。无论您做什么,都不会在 handling上使用它作为示例。它使我的眼睛厌恶地流泪。这样的代码是一个等待发生的错误。
发布于 2015-07-31 14:49:55
您没有在writeBuffer()方法中写入任何内容。
您可以使用类似于bytes.put(b)的东西。
发布于 2019-10-18 15:57:34
虽然这个问题在很久以前就已经被回答了,但让我也补充一些信息。这里。
writeBuffer()和readBuffer()方法分别存在两个问题,导致您无法获得预期的结果。
1) writeBuffer() 方法
正如上面的Maarten所解释的那样,不能直接使用byteBuffer.array()读取字节缓冲区数组中的流
或者,如果希望继续测试InputStream和ByteBuffer之间的关系作为示例(这也是服务器端应用程序处理传入消息的常见做法),则需要额外的字节数组。
2) readBuffer()方法
原始代码很好地使用额外的字节数组来检索字节缓冲区中的上下文,用于打印上下文。
但是,这里的问题是不正确地使用flip()和position()方法。
flip()方法只应在您希望将字节缓冲区的状态从storing context更改为exporting context之前调用。因此,这里的方法应该出现在bytes.get(b);行的正前方。在提供的示例中,在行byte[] b = new byte[bytes.position()];之前调用此方法为时尚早,因为flip()方法将字节缓冲区的位置标志更改为0,同时将限制标志设置为当前位置。int pos = bytebuffer.position();
2.2可能影响其位置标志的字节缓冲区处理:例如,bytebuffer.get(byte[] dst)等。
2.3将字节缓冲区的位置标志恢复为原始值:即bytebuffer.position(pos);在这里,我稍微修改了示例代码,以实现您想要做的事情:
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
public class TestBuffer {
private ByteBuffer bytes;
private String testStr = "Stackoverflow is a great place to discuss tech stuff!";
public TestBuffer() {
bytes = ByteBuffer.allocate(1000);
System.out.println("init: " + printBuffer());
}
public static void main(String a[]) {
TestBuffer buf = new TestBuffer();
try {
buf.writeBuffer();
} catch (IOException e) {
e.printStackTrace();
}
buf.readBuffer();
}
// write testStr to buffer
private void writeBuffer() throws IOException {
byte[] b = testStr.getBytes();
BufferedInputStream in = new BufferedInputStream(new ByteArrayInputStream(b));
// in.read(bytes.array());
byte[] dst = new byte[b.length];
in.read(dst);
bytes.put(dst);
in.close();
System.out.println("write: " + printBuffer());
}
// read buffer data back to byte array and print
private void readBuffer() {
//bytes.flip();
byte[] b = new byte[bytes.position()];
//bytes.position(0);
int pos = bytes.position();
bytes.flip(); // bytes.rewind(); could achieve the same result here, use which one depends on whether:
// (1) reading to this bytebuffer is finished and fine to overwrite the current context in this bytebuffer afterwards: can use flip(); or
// (2) just want to tentatively traverse this bytebuffer from the begining to current position,
// and keep writing to this bytebuffer again later from current position.
bytes.get(b);
bytes.position(pos);
System.out.println("data read: " + new String(b));
System.out.println("read: " + printBuffer());
}
public String printBuffer() {
return "ByteBuffer [limit=" + bytes.limit() + ", capacity=" + bytes.capacity() + ", position="
+ bytes.position() + ", remaining=" + bytes.remaining() + "]";
}
}https://stackoverflow.com/questions/31749025
复制相似问题