자바 ByteBuffer의 데이터 읽기

조회수 994회
Scanner sc = new Scanner(System.in);

System.out.print("Source File: ");
Path src = Paths.get(sc.nextLine());

System.out.print("Copy Name: ");
Path dst = Paths.get(sc.nextLine());

ByteBuffer buff = ByteBuffer.allocate(1024);

try (FileChannel rc = FileChannel.open(src, StandardOpenOption.READ);
     FileChannel wc = FileChannel.open(dst, StandardOpenOption.WRITE)) {
    int num;

    while (true) {
        num = rc.read(buff); <--- !

        if (num == -1) {
          break;
        }

        buff.flip();
        wc.write(buff);

        buff.clear(); <--- !
    }

} catch (IOException e) {
    e.printStackTrace();
}

원본 파일을 다른 이름으로 복사하는 코드인데요.

여기서 buff.clear() 메소드를 지우면 무한 루프가 발생합니다. 제가 궁금한 것은 왜 무한 루프가 발생하는지 입니다.

buff.clear()를 호출했을 땐, while문 맨 위의 read() 메소드가 파일을 다 읽었을 시 -1을 반환합니다. 그래서 if문에 의해 break가 이루어집니다.

그러나 buff.clear()를 호출하지 않았을 때는, 파일을 다 읽어도 read() 메소드가 0을 반환해서 if문에 걸리지 않습니다.

-1을 반환하는 것과 0을 반환하는 것에는 무슨 조건 차이가 있는 건가요? 그리고 이게 clear() 메소드와 무슨 관계가 있는지 궁금합니다.

  • (•́ ✖ •̀)
    알 수 없는 사용자

1 답변

  • 스트림 처리의 기본을 익히면 이해가 되실 겁니다.

    read 메소드의 설명입니다. 그중 리턴값의 설명을 보면 리턴값은 읽어낸 바이트의 수 입니다. 즉 버퍼를 비우지 않았다면...버퍼가 꽉 차 있으므로 더 읽어서 저장할 수가 없는 것입니다. 즉 read 한 바이트수는 0 이라는 겁니다.

    또한 결과가 0 이라는 의미는 해당 스트림을 통해 읽어낼 것이 더 있다는 의미입니다.

    버퍼가 비어 있어야 read가 바이트를 읽어내어 버퍼에 쓰고 그 크기를 리턴할 수 있습니다.

    public abstract int read(ByteBuffer dst)
                      throws IOException
    Reads a sequence of bytes from this channel into the given buffer.
    Bytes are read starting at this channel's current file position, and then the file position is updated with the number of bytes actually read. Otherwise this method behaves exactly as specified in the ReadableByteChannel interface.
    
    Specified by:
    read in interface ReadableByteChannel
    Specified by:
    read in interface SeekableByteChannel
    Parameters:
    dst - The buffer into which bytes are to be transferred
    Returns:
    The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream
    Throws:
    ClosedChannelException - If this channel is closed
    AsynchronousCloseException - If another thread closes this channel while the read operation is in progress
    ClosedByInterruptException - If another thread interrupts the current thread while the read operation is in progress, thereby closing the channel and setting the current thread's interrupt status
    IOException - If some other I/O error occurs
    
    • 답변 감사합니다. 그런데 여전히 헷갈리는 게 있습니다. 위 문서를 보면 파일의 끝에 도달하면 0 또는 1(possibly zero, or -1)을 반환한다고 쓰여 있는데, 둘 중에 무엇을 반환할지는 랜덤인건가요? 애초에 파일에서 읽을 게 없는데 버퍼가 꽉 차 있어도 상관없지 않나 해서요. 알 수 없는 사용자 2019.1.7 11:49
    • 그 부분은 read를 구현한 부분을 봐야 합니다. 버퍼가 이미 채워져 있다면 바로 0을 리턴하도록 구현되어 있을 수도 있습니다. 당연하겠지요. 버퍼에 쓸수 없는 상태라면 읽을 필요도 없을테니까요. 파일의 끝 eof 면 -1을 반환합니다. returns의 문장을 잘 보세요. 바이트의 읽은 크기의 수 혹은 만약 채널이 end-of-stream 면 -1이라고 되어 있어요. 정영훈 2019.1.7 12:29

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)