[ Kotlin Point ] 그래서 스트림이 도대체 뭔데?

malcongmalcom·2025년 6월 24일

Kotlin Point

목록 보기
1/4
post-thumbnail

피곤한 내 성격

이 글은 이 코드 한 줄에서 시작됐다.

val br = BufferedReader(InputStreamReader(System.`in`))
val input = br.readLine().toInt()

요즘 부스트캠프에서 동료들 코드를 자주 보게 되는데,

피어 피드백 중에 문득 저 코드가 눈에 걸렸다.

아니 도대체 BufferedReader랑 InputStreamReader, System.'in'은 무슨 관계야?

그렇게 또 한 번, 나의 집요한 호기심이 발동해버렸고...

오늘 하루는 스트림에 대한 의문을 끝까지 파헤쳐보기로 했다.

하...피곤하다...응원 댓글 좀 주세요...

하나씩 분해해보기

BufferedReader는 뭘까?

처음엔 그냥 "클래스겠지?" 했는데...

내 절친 G씨에게 물어봤더니 다음과 같이 이야기하더라.

"BufferedReader는 문자 스트림을 효율적으로 읽기 위해 버퍼를 사용하는 클래스입니다."

역시나 클래스.

근데 중요한 건 "문자 스트림"과 "버퍼"라는 말이다.

무슨 말일까?

스트림이라는 단어는 왜 이렇게 감이 안 오지?

스트림이라고 하면 "흐름"이라는데,

컴퓨터가 물에 떠다니는 것도 아니고 무슨 흐름?

난 이 개념이 너무 추상적으로 느껴졌다.

반면에 버퍼는 왠지 감이 온다.

"기다렸다가 처리하는 임시 저장 공간"이라는 느낌.

뭔가 감이 딱 온다.

그래서 내부에서 무슨 일이 벌어질까?

G씨에 따르면 BufferdReader 내부에서는 이런 일이 벌어진다.

  • 내부에 문자 배열 버퍼를 갖고 있음
  • 데이터를 읽을 때마다 OS에 요청하는 것이 아니라, 한 번에 여러 문자를 읽어서 버퍼에 저장함
  • 이후엔 버퍼에서 꺼내 쓰니까 빠르고 효율적임

즉, BufferedReader는 IO 요청을 최소화하고,

메모리에서 빠르게 읽기 위한 성능 최적화 도구인 거다.

  • read() : 문자 하나 읽기
  • readLine() : 한 줄 통째로 읽기 (\n, \r\n 포함 안 함)
  • close() : 스트림 닫기
  • ready() : 읽을 준비 됐는지 확인

그럼 왜 InputStreamReader(System.in)을 인자로 주는 걸까?

이 질문이 또 생긴다.

"왜 BufferedReader가 InputStreamReader를 인자로 받고,

그건 또 왜 System.in을 받는 건데?"

G씨가 핵심을 콕 짚어줬다.

G씨에 따르면 BufferedReader는 문자 스트림(Reader)을 인자로 받는데,

System.in은 바이트 스트림(InputStream)이라서

중간에 InputStreamReader가 바이트 → 문자로 변환해준다고 한다.

정확히 말하면 아래와 같은 구조다.

키보드 입력
↓ (바이트 단위)
System.in → InputStream (바이트 스트림)

InputStreamReader → Reader (문자 스트림)

BufferedReader → 문자 버퍼 + readLine()

사용자가 호출하면 문자열 반환

그럼 키보드를 누르면 내부에서 무슨 일이 벌어질까?

진짜 물리적인 이야기로 가보자.

우리가 키보드를 딱 누르면 내부적으로 다음과 같은 일들이 벌어진다.

  1. 기계적으로 스위치가 눌림
  2. 전기 신호가 발생 → 메인보드로 전달됨
  3. 키보드 안의 컨트롤러가 이걸 스캔 코드(숫자)로 바꿔줌
  4. OS는 이 스캔 코드를 받아서 유니코드 문자로 바꾸고
  5. 그 문자를 키보드 입력 버퍼(메모리 공간)에 저장함

근데 자바는 어떻게 저 버퍼에 접근하지?

자바는 JVM 위에서 동작하고, OS와는 독립적이어야 하는데

어떻게 OS의 키보드 입력 버퍼에 접근하지?

바로 여기에 답이 있다:

"네이티브 메서드"

System.in의 정체는 JVM에서 제공하는 InputStream 객체인데,

그 메서드 중 일부는 실제로 C나 C++로 구현된 OS 레벨의 네이티브 코드를 호출한다.

그래서 자바 코드가 OS의 입력 버퍼에 접근할 수 있는 거다.

그렇다면 결국 System.in은?

  • InputStream을 상속한 자바 클래스
  • 내부적으로는 네이티브 메서드로 OS 자원을 다룸
  • 실제론 키보드 입력 버퍼에서 바이트 단위로 데이터를 가져옴
val br = BufferedReader(InputStreamReader(System.`in`))
val input = br.readLine().toInt()

이 코드에서 가장 중요한 건 System.in

바로 OS와 JVM의 경계를 넘는 다리 역할을 한다.

InputStream의 주요 메서드

  • read() : 바이트 하나를 읽음. 읽은 바이트(0~255) 반환, 끝이면 -1 반환
  • read(byte[] b) : 바이트 배열 크기만큼 데이터를 읽어서 배열에 저장, 읽은 바이트 수 반환
  • read(byte[] b, int off, int len) : 배열 b의 off 위치부터 최대 len 바이트를 읽어 저장, 실제 읽은 바이트 수 반환
  • skip(long n) : 입력 스트림에서 n 바이트를 건너뜀
  • available() : 즉시 읽을 수 있는 바이트 수 반환
  • close() : 스트림을 닫아서 리소스를 해제함
  • mark(int readlimit) : 현재 위치를 표시해둠 (나중에 reset()으로 돌아오기 위함)
  • reset() : mark()한 위치로 돌아감
  • markSupported() : 마크 기능을 지원하는지 여부 반환

InputStreamReader / BufferedReader는 래퍼 클래스다

이 둘은 결국 흔히 말하는 "래퍼 클래스(wrapper class)"다.

즉, 다른 스트림을 감싸서 기능을 확장하거나 변환해주는 역할이다.

  • InputStreamReader는 바이트 → 문자 변환기 (어댑터)
  • BufferedReader는 성능 향상을 위한 버퍼 + 줄 단위 읽기 제공 (데코레이터)

그런데 재밌는 건

"BufferedReader의 '버퍼'는 키보드 입력 버퍼가 아니라, 클래스 내부 버퍼라는 점!"

이게 헷갈리기 쉬운 포인트다.

부록: 스트림 관련 클래스

  • InputStream : 바이트 기반 입력 스트림을 처리하는 추상 클래스
  • OutputStream : 바이트 기반 출력 스트림을 처리하는 추상 클래스
  • Reader : 문자 기반 입력 스트림을 처리하는 추상 클래스
  • Writer : 문자 기반 출력 스트림을 처리하는 추상 클래스
  • FileInputStream : 파일을 바이트 단위로 읽는 입력 스트림 클래스
  • InputStreamReader : 바이트 스트림을 문자 스트림으로 변환해주는 클래스
  • BufferedReader : 문자 스트림에 버퍼링과 readLine() 기능을 추가한 클래스

정리하자면

스트림은 결국 그냥 추상화된 개념일 뿐이다.

실제로 벌어지는 일은 다음과 같다.

  1. OS에 있는 키보드 입력 버퍼에 키가 들어오고
  2. JVM은 네이티브 메서드로 그걸 읽어오고
  3. System.in이 바이트 스트림으로 데이터를 전달하고
  4. InputStreamReader가 바이트를 문자로 바꾸고
  5. BufferedReader가 그걸 버퍼에 모아서 효율적으로 읽을 수 있게 해준다.

스트림이라는 건 결국 이런 입출력 동작을 추상화한 개념이고,

실제론 이런 역할을 하는 클래스들의 조합이다.

마무리하며

컴퓨터의 모든 입력은 물리에서 시작해,

OS를 거쳐, JVM을 지나, 우리가 호출하는 readLine()에 도달한다.

그 과정이 이렇게 정리되고 이해될 때,

비로소 나는 저 한 줄의 코드가 단순하지 않음을 느낀다.

하나에 꼳히면 끝까지 파고드는 이 성격...피곤하지만,

그래도 이렇게 정리해두면 다음부터는 좀 덜 피곤하겠지...

이 글이 누군가에게 도움이 되었으면 좋겠다!

필요하면 아래에 댓글로 질문 남겨주세요.

조언도 너무 감사합니다. 지적에 목마릅니다.

칭찬도 감사하지만 조언이나 지적은 배로 감사합니다.

안드로이드 개발자 화이팅!

Peace, Love.

profile
안녕하세요. 날씨가 참 덥네요.

0개의 댓글