자바 Stream

황희윤·2023년 11월 27일

Stream

순서가 있는 데이터의 연속적인 흐름

  • 장치프로그램 사이를 연결하는 가상의 파이프로, 이 파이프를 통해 바이트들이 순서대로 이동

  • 장치(키보드, 모니터)는 서로 제어하는 방법이 각각 다르지만, Stream이라는 공통적인 입출력 모델을 적용하면 입출력을 동일한 방식으로 처리할 수 있다.

  • System.out.print() 같은 메서드는 콘솔이라는 독립적인 장치로부터 문자 기반으로 데이터를 전송하는데, 프로그램과 콘솔은 완전히 떨어져 있기 때문에 Stream이 연결 고리 역할을 해준다.

입출력

  • 입력 : 외부 장치에서 컴퓨터의 주기억 장치로 데이터가 이동

  • 출력 : 컴퓨터의 주기억 장치에서 외부 장치로 데이터가 이동

  • 프로그램이 실행되는 동안 사용하는 데이터는 모두 읽고 쓰기가 가능한 메모리(RAM)에 저장된다.


Stream 특징

1. FIFO (First In First Out)

  • 먼저 입력되는 데이터가 먼저 출력되는 형태로 순차적 접근만 가능하다.

2. 단방향

  • 하나의 Stream으로 입출력을 동시에 수행하지 못한다.

  • 양방향 전송이 필요하면 출력 Stream과 입력 Stream 각각이 필요하다.


Stream 두 가지 분류

1. 데이터에 따른 분류

바이트 기반 Stream

  • 데이터를 1바이트(8비트) 단위로 전송한다.
  • InputStreamOutputStream 추상 클래스가 최상위 클래스
  • 파일과 객체, 기본 자료형의 입출력에 사용한다.

문자 기반 Stream

  • 데이터를 2바이트 단위로 전송한다.
  • ReaderWriter 클래스가 최상위 클래스
  • 문자만 입출력 가능
  • Reader 클래스는 특정 인코딩을 읽어서 유니코드로 변환해 주고 Writer 클래스는 유니코드를 특정 인코딩으로 변환한다.
  • 인코딩(encoding) : 데이터를 Stream 형식으로 변환해 보조 기억 장치나 네트워크에서 사용 가능하게 만드는 작업
    • ANSI(미국표준), UTF-8(한국표준)

2. 기능에 따른 분류

1차 Stream

  • 실제 데이터를 주고받는 입출력 통로(논리적인 흐름이나 파이프)를 직접 생성
  • 기본 기능을 담당하며 대상과 직접 데이터를 주고받는다.
  • ex) 하드디스크에 저장된 파일(before.txt)를 읽어서 메모리에 저장 후, 다시 다른 파일(after.txt)로 저장하는 기능(FileInputStream & FileOutputStream)
    • FileInputStream 객체는 파일에서 한 바이트씩 읽는다.
    • 이 때 read() 메서드를 사용해서 읽어들인 한 바이트는 정수형을 반환한다.
    • FileOutputStream은 데이터를 바이트 단위로 파일에 저장한다.
    • 이 때 write() 메서드를 사용해서 저장되는 한 바이트는 정수형으로 반환된다.
    • 바이트 단위로 읽거나 쓰기 때문에 다양한 종류의 파일에서 사용할 수 있다.

2차(보조) Stream

  • 1차 Stream에 새로운 기능을 추가해 확장한 Stream
  • 1차 Stream이나 다른 2차 Stream에 붙어서 효율성을 높인다.
  • 자체만으로는 입출력을 수행하지 못한다.
  • ex) 키보드에서 입력받은 문자 데이터를 버퍼에 담아 읽는 방법
InputStream bIn = new BufferedInputStream(System.in);
// BufferedInputStream = 2차 Stream
// System.in = 1차 Stream
  • BufferedInputStream 객체를 사용해서 데이터를 1바이트 단위로 읽어들이는 read() 메서드를 실행하면 시스템 내부적으로 버퍼를 준비하고, 이 버퍼를 사용하여 키보드에서 입력받은 데이터에서 버퍼의 크기만큼 한꺼번에 많은 데이터를 가져온다.

  • 이렇게 채워진 버퍼(buffer)로부터 1바이트씩 읽어들여 프로세스로 전달한다.

  • 키보드 문자열 ➡️ 한 바이트 씩 전송 ➡️ BufferedInputStream 객체에 담겨서 전송된 데이터는 버퍼에 담아 한꺼번에 처리 ➡️ read() 메서드로 1바이트씩 프로세스로 전달됨

  • 버퍼(buffer) : 임시 저장소로 데이터를 목적지로 바로 보내지 않고 중간에 입력이나 출력 버퍼를 두고 전송한다.

    • 문자를 그룹으로 묶어서 전송하는 것이 하나씩 전송하는 것보다 시간을 적게 소모한다.
    • 버퍼를 사용하면 잘못된 입력이나 출력과 같은 실수를 수정할 수 있다.
  • 버퍼링(buffering) : 바이트당 오버헤드(overhead)를 최소화하는 기법

    • 자바에서는 운영체제 자체의 함수를 호출하는데, 이 때 발생하는 비용이 한 번에 한 바이트를 보내는 것이나 여러 바이트를 보내는 것이나 차이가 없다.
    • 한 바이트씩 여러 번 보내면, 많은 비용이 발생한다.
    • 자바에서는 원래 스트림을 버퍼 스트림으로 감싸면서 버퍼링을 쉽게 적용한다.
  • new BufferedInputStream(System.in)처럼 기존의 기능에 추가 기능을 더하는 프로그래밍 패턴을 Decoration 패턴이라고 한다. IO 클래스가 대표적이다.


직렬화(serialization)

자바 객체를 하드디스크에 저장하거나 네트워크로 전송하기 위해 바이트 배열로 변환하고, 또 역으로 저장되거나 전송받은 바이트 배열을 자바 객체로 변환하는 기술

  • 데이터를 Stream에 전송할 수 있도록 바이트 단위로 그리고 일렬로 변환하는 작업

  • 마샬링(marshalling)이라고도 한다.

객체 전송 과정

1. 직렬화 : 객체를 바이트 단위로 나눈다.

2. 직렬화되어 나누어진 데이터를 순서대로 전송한다.

3. 역직렬화 : 전송받은 데이터를 원래대로 복원한다.

직렬화가 가능한 객체의 조건

  1. 기본 자료형(boolean, char, byte, short, int, long, float, double)은 직렬화가 가능하다.

  2. Serializable 인터페이스를 구현한 객체도 가능하다.

    • ex) Vector 클래스
    • Serializable 인터페이스는 아무런 메서드가 없고 단순히 JVM에게 정보를 전달하는 기능만 있다.
  3. transient 제어자가 사용된 속성(멤버 변수)은 전송되지 않는다.

    • 직렬화는 보안이 잘 되지 않아서 안전하지 않다.
    • 직렬화하고 싶은 과정에서 제외하고 싶은 속성에 사용한다.
    • ex) 패스워드와 같은 민감한 정보
profile
HeeYun's programming study

0개의 댓글