
Stream은 데이터가 흐르는 통로를 추상화한 개념이다. 외부와 데이터를 주고 받을 때 데이터가 한번에 처리되는 것이 아닌 순차적으로 전달된다.
Java에서 Stream은 이런 데이터 흐름을 일관된 방식으로 다룰 수 있도록 만든 추상화 계층이다. 실제 데이터의 출처에 상관없이 동일한 방식으로 읽고 쓸 수 있게 만든 구조다.
Java에서 Stream은 크게 ‘Byte Stream’과 ‘Character Stream’으로 나뉜다. Byte Stream은 1byte 단위로 데이터를 처리하며 모든 데이터를 처리할 수 있다. Character Stream은 문자 단위(2Byte)로 데이터를 처리하며 내부적으로 문자 인코딩 처리 방식을 포함한다.
Buffer는 메모리에 임시로 데이터를 저장하는 공간이다. I/O 작업은 메모리에 비해 상대적으로 느리다. 스트림을 사용하여 1byte 단위로 처리한다면 많은 시스템 콜을 요청하면 성능이 급격하게 저하된다. 이때 일정량을 모아 한번에 처리하도록 하기 위해 버퍼가 등장했다.

BufferedOutputStream을 보면 내부적으로 기본 8192 byte(8KB) 크기의 버퍼를 가지고 있다.
이 버퍼는 write 요청이 들어올 때마다 바로 하위 스트림으로 데이터를 전달하지 않고, 일정량을 내부에 모아두는 역할을 한다.
BufferedOutputStream 은 다음 경우에 하위 스트림으로 실제 전달이 발생한다.
작은 단위의 write 호출이 여러 번 발생하더라도 실제 I/O는 한 번에 처리될 수 있다.
Stream과 Buffer는 각각 역할과 특성이 다르며, 상황에 맞게 함께 사용하는 것이 중요하다. Stream은 데이터의 흐름을 추상화하여 순차적으로 처리하며 입력과 출력이라는 방향성을 가진다. 반면 Buffer는 데이터를 일정량 모아 한 번에 처리함으로써 I/O 호출 횟수를 줄이고 전체적인 성능을 향상시키는 역할을 한다.