🥭 개요
소프트웨어 개발에서 데이터의 효율적인 처리는 필수적이다. 특히 데이터 입출력은 애플리케이션의 성능과 사용자 경험에 직접적인 영향을 미친다. 특히 자바에서의 데이터 입출력은 주로 스트림을 통해 이루어진다. 여기서 이 기본 스트림의 개념과 버퍼스트림이 중요한 이유에 대해서 소개하고자 한다.
🍐 스트림의 기본 개념
스트림이란 단어의 원래 의미는 “물이 흐르는 곳”이다. 자바에서는 데이터가 연속적으로 흐르는 경로를 의미한다. 컴퓨터는 스트림을 데이터의 연속적인 흐름으로 보며, 이를 통해 프로그램이 순차적으로 데이터를 읽거나 쓸 수 있다. 스트림의 소스와 목적지는 파일이지만, 네트워크나 입출력 장치, 또는 객체와도 연결 될 수 있다.
입/출력 스트림
위의 그림처럼 스트림에는 크게 입력 스트림과 출력스트림으로 구분 할 수 있다. 이는 자바시스템에서 데이터의 흐름을 관리하는 주된 방법이고, 이를 통해 프로그램이 파일, 네트워크 메모리 등 다양한 소스와 목적지에서 데이터를 읽고 쓸 수 있도록 도와 준다. 그리고 이 데이터 처리의 차이에 따라 바이트 스트림과 문자 스트림으로 나누어 진다.
- 바이트 스트림
바이트 스트림은 이진 데이터를 처리하기 위한 스트림이다. 8비트 단위로 입출력하기 때문에 인코딩을 고려하지 않는다. 데이터를 원시 바이트 형태로 처리하며, 텍스트와 비텍스트 모두에 사용가능하다. 특히 이미지, 오디오 파일, 실행 파일등 이진 데이터 처리에 적합하다.
- 문자 스트림
문자 스트림은 문자 데이터를 처리하기 위한 스트림이다. 문자를 인코딩하고 디코딩하는 과정을 처리하며, 텍스트 데이터에 최적화 되어있다. 문자 스트림의 인코딩 처리는 UTF-8이나 UTF-16과 같은 문자 인코딩을 지원하고, 다양한 언어의 문자를 올바르게 처리할 수 있다.
하지만 이런 시스템의 스트림방식은 여러 가지 문제가 발생할 수 있다. 즉, 데이터를 바이트/문자 단위로 자주 읽고 쓰는 경우 비효율적이게 된다. 마치 같은 반 친구가 먹고 있는 과자을 먹는 다 생각해보면, 과자를 한 개씩 먹으면서 여러번 왔다갔다 하는 것과, 한 번가서 한 주먹만큼 들고와서 먹는다고 상상해볼 수 있다. 바로 바이트/문자 단위의 스트림은 과자를 한 개씩 먹을 때 마다 왔다갔다 해야되기 때문에 비효율적이다. 하지만 지금 소개할
버퍼스트림
은 과자를 한 번에 담아와서 한 개씩 꺼내먹는 모습을 상상할 수 있다. 🍅 버퍼 스트림이 중요한 이유
버퍼 스트림(Buffered Stream)은 데이터를 일시적으로 저장하는 메모리 영역인 ‘버퍼’를 사용하여 데이터 스트림을 처리하는 방식이다. 버퍼스트림은 버퍼를 사용해 데이터를 일정량 모은 후에 한 번에 처리한다. 이렇게 중간에 버퍼를 이용해 디스크나 네트워크로 부터 데이터를 읽고 쓰는 작업을 더 효율적으로 수행할 수 있게 해준다. 만약 버퍼스트림을 사용하지 않을 경우, 다음과 같은 여러 가지 문제가 발생할 수 있다.
🙄 버퍼트스림을 사용하지 않을 때 발생할 수 있는 문제점
- 효율성 저하 :
버퍼 스트림을 사용하지 않으면, 데이터를 작은 단위로 자주 읽고 쓰게 되어 시스템 호출이 증가하고, 이는 전체적인 입출력 효율성을 저하시킨다.
- 문자 인코딩 문제 :
바이트 스트림에서는 글로벌한 통신 환경에서 많은 문제를 일으킨다. 이것은 바이트는 8비트씩 끊어서 데이터를 읽기 때문인데, 8비트로 표현할 수 있는 영어가 아닌 다른 외국어를 읽을 수 없게 되므로 의미없는 데이터가 되어 버린다. 그리고 영어를 사용한다고 하더라도 바이트 스트림과 문자스트림은 8비트/16비트로 끊어서 읽기 때문에 합의가 되지 않은 인코딩은 문자열은 유실시킬 수 있다.
- 스트리밍 불안정성:
실시간 데이터 스트리밍의 경우, 버퍼링 없이 데이터를 전송하면 네트워크 지연이나 변동성등 여러가지 요인으로 끊김이나 지연과 같은 문제가 발생할 수 있다.
- 자원 사용량 증가:
버퍼 스트림을 사용하지 않으면, 시스템은 더 많은 입출력 연산을 수행해야 하므로, CPU와 메모리 자원 사용량이 증가할 수 있다.
🧐 버퍼 스트림 사용 문법에서의 주의점
버퍼 스트림은 바이트 스트림과 문자 스트림의 한계를 보완해주는 보조 스트림으로 큰 역할을 한다. 이로 인해 시스템이 효율성이 향상하고 데이터의 손실이 방지 된다. 하지만 버퍼스트림을 사용하는 데 있어서 문법적으로 주의해야될 사항이 있다.
예시 코드
위의 예시의 데이터 통신 환경에 있어서 해당 예시 코드가 클라이언트 쪽에서 작성된 코드이고 해당 정보를 서버측에서
readLine()
메소드로 정보 입력을 기다리고 있는 상태라고 해보자. 하지만 클라이언트가 위의 코드 문법대로 작성되지 않는 다면 정보 유실을 유발하게 된다. - flush( ) 메소드
flush( ) 메소드는 버퍼에 저장된 데이터를 강제로 출력 스트림으로 전송한다. 버퍼가 다 채워지기 전에 데이터를 전송해야 할 때 이 메소드를 사용한다. 이렇게 사용하지 않으면 클라이언트-서버 애플리케이션에서 서버로 즉각적인 응답이 필요한 경우 버퍼가 가득 찰 때까지 데이터를 받지 못하고 대기하게 된다.
- ‘\n’ (개행 문자)
‘\n’ 개행 문자를 사용하지 않으면 라인 기반의 읽기 작업에 문제가 발생한다. 많은 읽기 함수들이 개행 문자를 라인의 끝으로 인식하기 때문에, 이를 포함하지 않으면 다음 라인으로 넘어가지 않는다. 따라서 개행 문자 없이 전송한다면, 애플리케이션은 데이터의 끝을 인식하지 못하고 무한 대기 상태에 빠지게 된다.
Share article