すでに他の回答が指摘しているとおり、read
メソッドで更新されるバッファの位置を考慮する必要があります。あなたの特別な場合には、arrayOffset()
は常にゼロになりますが、あなたはより良いあなたがバッファに何かを変更したときに、それは壊れていないこと、方法でコードを書くこと
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++;
}
注:だから、正しいコードは次のようになります割り当てコード。
しかし、このコードは壊れています。複数バイトのUTF-8シーケンスを読み込むと、そのシーケンスの最初のバイトが1回の操作で読み取られ、残りのバイトが次のバイトで読み取られることがあります。これらの不完全なシーケンスからインスタンス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機能ではありません)。 Stringbuilder.append
操作ではバッファからすべての文字を消費することがわかっているため、clear()
を使用する必要があります。
このコードでは、任意の数のread
の後に停止するため、特定の(やむを得ない)エラー条件を処理しないことに注意してください。マルチバイトUTF-8シーケンスの途中で切り捨てることは常に可能です。
しかし、これは非常に複雑なロジックは、すでにJREによって実装されていて、あなたがバイトの特定の番号の後に切断のアイデアをあきらめた場合、あなたはそれを利用することができます:今
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で手渡されました。
Eh?すべてのデータをクリアするのはまさにそのためです。あなたの問題は、文字列を配列全体から直接構築するだけで、読み込みの長さを無視してしまうことです。 – EJP