다른 답변에 의해 이미 지적했듯이 read
메서드로 업데이트되는 버퍼의 위치를 고려해야합니다. 당신의 특별한 경우에, arrayOffset()
은 항상 0이됩니다,하지만 당신은 더 나은 당신이 버퍼에 무언가를 변경할 때 중단하지 않는, 방식으로 코드를 작성하는 것이
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 시퀀스를 읽으면 해당 시퀀스의 첫 번째 바이트가 한 번의 작업에서 읽히고 나머지 바이트는 다음 바이트에서 읽혀 질 수 있습니다. 이러한 불완전한 시퀀스로 인해 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
으로 사용하는 것입니다.
NIO 기능이 아니기 때문에 유일한 예외는 Stringbuilder
에 추가됩니다. 여기서 우리는 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
들입니다 여전히 NIO를 사용하여 문자 데이터를 읽는 표준 방식. 대체품이 없다. method Reader.read(CharBuffer)
은 NIO의 첫 번째 릴리스에서는 누락되었지만 Java 5에서는 수령되었습니다.
Eh? 모든 데이터를 지우는 것이 정확히 무엇을위한 것입니다. 문제는 전체 배열에서 문자열을 직접 작성하여 읽기 길이를 무시한다는 것입니다. – EJP