Stream, Buffer

Jan 08, 2024
Stream, Buffer
 

1. 스트림(Stream)

💡
단어의 뜻은 ‘물이 흐르는 개울’ 이다. 자바에서는 ‘바이트들의 연속적인 흐름’을 스트림이라고 한다.
 
 
컴퓨터의 구조는 크게 다음과 같이 하드웨어 - OS - Application 로 구성되어있다.
하드웨어인 키보드로 값을 입력하면 OS 를 통해 Application 으로 전달되고, 다시 Application 에서 OS를 통해 모니터로 출력된다. 이 과정을 스트림이라고 한다.
 
 
notion image
 
 
키보드, 마우스 같은 외부 장치에서 값을 입력하는 과정은 InputStream,
값을 외부장치로 출력하는 과정을 OutputStream 이라고 한다.
 
이 스트림 과정을 자세하게 그려보자.
 
notion image
 
어플리케이션에서 전송된 데이터는 파일을 통해 OS 로 전송되는데 이 과정을 Byte Stream 이라고 한다. (이 파일은 다른 하드웨어로 정보를 전달하는 통신에서는 소켓으로 불린다.)
 
파일에 데이터값이 입력되면 파일에 입력받은 값이 저장되었다 OS에 전달되고 사라진다. 그 다음 새로운 값을 저장 후 OS에 전달 후 또 사라진다.
 
public class StreamEx01 { public static void main(String[] args) { InputStream input = System.in; try { System.out.print("문자를 입력하세요:"); int value = input.read(); System.out.println("받은 값:" + (char) value); } catch (IOException e) { throw new RuntimeException(e); } } }
 
InputStream 은 입력 기반 스트림의 최상의 클래스이다. 반대로 출력은 OuputStream 이다.
System.in 은 키보드로부터 값을 입력받는 코드이다.
 
notion image
 
해당 코드를 실행한 결과이다. ABCED 값을 입력했지만 A값만 출력된다.
스트림은 끝이없는 Byte의 흐름이다. 따라서 파일에서 값을 OS로 전달할 때 , 동시에 전달되지 않기 때문에 대기 중인 값들은 소멸해버린다. 그래서 대공간인 보조스트림이 필요하다.
 

2. 보조스트림

💡
Application 과 파일 사이에서 Byte가 대기할 공간. 사용할 필요는 없다.
notion image
보조스트림은 어플리케이션에서 파일로 데이터가 전달될 때 값을 잠시 저장하는 공간이다.
보조데이터의 크기는 개발자가 임의로 정할 수 있다.
 
public static void main(String[] args) { InputStreamReader ir = new InputStreamReader(System.in); char[] ch = new char[4]; try { System.out.print("문자를 입력하세요:"); ir.read(ch); for (char c : ch) { System.out.print(c + ""); } } catch (IOException e) { throw new RuntimeException(e); } }
 
InputStreamReader 은 입력받은 값을 문자로 변환할 수 있다. 변환된 값은 배열로 저장한다.
 
notion image
값을 입력하면 배열의 크기만큼 값이 출력되고 나머지 데이터는 소멸한다.
보조스트림이 있어도 배열의 크기는 변경이 되지 않기 때문에 입력될 값의 크기가 개발자가 정한 보조스트림의 크기 이상이 되면 남은 데이터는 소멸된다. 임의로 대량의 크기를 지정할 수 있지만 메모리 낭비기 때문에 효율적이지 않다. 이를 해결하기 위해 버퍼(Buffer) 를 이용한다.
 

3. 버퍼(Buffer)

💡
데이터를 한 곳에서 다른 한 곳으로 전송하는 동안 일시적으로 그 데이터를 보관하는 메모리 영역
 
버퍼링이라는 말을 자주 들어봤을 것이다. 게임이나, 동영상을 볼 때 실행되지 않고 잠시 멈춘 상태일 때 버퍼링 걸렸다고 한다.
버퍼는 임시 저장소에서 값을 처리하고 있기 때문에 데이터가 소멸되지 않고 순차적으로 처리된다.
notion image
public static void main(String[] args) { InputStreamReader ir = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(ir); try { System.out.print("문자를 입력하세요:"); String line = br.readLine(); System.out.println(line); } catch (IOException e) { throw new RuntimeException(e); } }
 
읽기 버퍼(BufferedReader) 를 통해 버퍼를 만들고, readLine 으로 값을 읽는다.
버퍼를 이용하면 파일에서 값이 전송되는 동안 버퍼에서 대기하기 때문에 입렭된 값이 전부 출력된다.
 
notion image
 

4. 쓰기 버퍼(BufferedWriter)

 
3번에서 쓰기 버퍼를 사용해 값을 입력해보자.
 
public static void main(String[] args) { BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); try { bw.write("안녕\n"); // \n 내려쓰기 통신은 한번 읽을때 \n까지 읽음. \n 을 두번 쓰면 두번 readline 해야됨. bw.write("반가워\n"); // 통신에서 \n을 보내줘야 됨. \n 이 없으면 안읽어서 통신이 안됨. 가긴하는데 상대가 못읽음. 가장 마지막에 \n 은 넣어야됨 } catch (IOException e) { throw new RuntimeException(e); } }
 
notion image
 
BufferedWriter 를 통해 값을 입력했다. 하지만 값이 출력되지 않는다.
이는 물이 위에서 아래로 흐르는 것과 비슷하다. 호수에 물이 충분하다면 자연스럽게 아래로 흐르겠지만, 물이 충분하지 않다면 웅덩이에 고여있을 것이다. 그래서 강제로 흘려보내야 되는데 이때 사용하는 것이 flush() 메서드이다.
flush() // 수도꼭지 처럼 틀어야 물이 나오는 것 처럼 데이터를 강제로 보낸다.
 
notion image
버퍼 사이즈
 
 
 
public static void main(String[] args) { BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); try { bw.write("안녕\n"); bw.write("반가워\n"); bw.flush(); } catch (IOException e) { throw new RuntimeException(e); } }
notion image
 
 
💡
통신에서 중요한 점은 데이터를 보낼 때 \n 을 반드시 포함해야 한다. 읽기버퍼에서 readLine를 사용하는데 \n이 없다면 값을 읽을 수 없다. “안녕 반가워” 에서 “안녕\n” “반가워” 로 보내면 안녕만 읽고 ‘반가워’는 읽지 않는다. 따라서 데이터의 가장 마지막 값에는 반드시 \n 을 넣어야 한다.
 
Share article

{CODE-RYU};