[Java] 보조 스트림의 사용

지니·2025년 3월 16일

JAVA

목록 보기
7/9
post-thumbnail

1. 보조 스트림이란?


기반 스트림을 보조해 기능을 향상시키거나 새로운 기능을 추가해주는 역할을 하는 것이다.

  • 보조 스트림은 스스로 입출력 처리가 불가능하기 때문에, 기반 스트림과 연결해서 사용해야 한다.
  • 기본 스트림만 사용할 때보다 더 효율적이고 편리한 입출력 처리가 가능하다.
  • 코딩 테스트에서 성능 향상을 위해 Scanner와 System.out.println(); 대신에 사용되기도 한다.

2. 버퍼 보조 스트림


2-1. Buffer

데이터를 임시 저장하는 공간으로 입출력의 속도를 향상시키기 위해 사용한다.

⁉️그렇다면 왜 속도가 향상될까?

예를 들어, 마트에서 10개의 물건을 사야 한다고 생각하자. 이 때, 물건을 하나씩 가져와 계산하는 것과 구매해야 하는 물건을 한 번에 장바구니에 담아서 결제하는 것 둘 중에 뭐가 더 빠를까? 당연히 후자가 훨씬 빠르다.

이와 비슷하게 사용자가 요청할 때마다 데이터를 읽거나 출력하는 것보다, 사용자의 요청을 한번에 받고 데이터를 읽거나 출력하는 것이 속도면에서 훨씬 이득인 것이다. 즉, 장바구니의 역할을 해주는 것이다.

2-2. Buffer 스트림의 종류

'버퍼를 사용한 입출력' 클래스에는 2가지 종류가 있다.

  • BufferedInputStream/BufferedOutputStream : 바이트 스트림용
  • BufferedReader/BufferedWriter : 문자 스트림용

2-3. BufferedReader/BufferedWriter 사용

import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        // BufferedWriter 사용 (파일 쓰기)
        BufferedWriter bw = new BufferedWriter(new FileWriter("test.txt"));
        bw.write("안녕하세요.\n");
        bw.write("반갑습니다.\n");
        // 버퍼를 이용하는 경우 버퍼가 가득 차면 자동으로 내보내기를 하지만
        // 가득 차지 않은 경우 flush()로 내보내기를 해야 출력이 된다.
        // flush 없이 그냥 close만 사용해도 된다.
		// bw.flush();
        bw.close();  // 자원 해제

        // BufferedReader 사용 (파일 읽기)
        BufferedReader br = new BufferedReader(new FileReader("test.txt"));
        String line;
        // 읽을 내용이 없을 때까지 읽어와서 출력하기
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        br.close();  // 자원 해제
    }
}

3. 형변환 보조 스트림


기반 스트림이 byte, 보조 스트림이 char 스트림인 경우 이를 문자 스트림으로 변환하는 역할을 하는 보조 스트림

3-1. InputStreamReader

바이트 스트림을 문자 스트림으로 변환

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  • System.in은 바이트 스트림(InputStream) 형태로 표준 입력 받는다.
  • InputStreanReader를 사용해 바이트 스트림을 문자 스트림으로 변환한다.
  • 변환된 문자 스트림을 BufferedReader에 넘긴다.

System.in(바이트) → InputStreamReader(문자로 변환) → BufferedReader(문자)

3-2. OutputStreamWriter

문자 스트림을 바이트 스트림으로 변환

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
  • System.out은 바이트 스트림 (OutputStream) 형태로 표준 출력을 수행한다.
  • OutputStreamWriter를 사용해 문자 스트림을 바이트 스트림으로 변환한다.
  • 변환된 바이트 스트림을 BufferedWriter에 넘긴다.

✅ BufferedWriter(문자) → OutputStreamWriter(바이트로 변환) → System.out(바이트)


3-3. 형변환 보조 스트림 사용

import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        // 표준 입력 스트림 사용 (InputStreamReader & BufferedReader)
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String value = br.readLine(); // 콘솔로부터 문자열 입력 받기
        System.out.println("입력 받은 문자 : " + value);
        br.close(); // 자원 해제

        // 표준 출력 스트림 사용 (OutputStreamWriter & BufferedWriter)
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        bw.write("출력 테스트");
        bw.close(); // 자원 해제
    }
}

4. 데이터 보조 스트림


바이트 기반의 입출력 스트림을 보조해, 자바의 기본 자료형에 맞게 자료를 입출력 하는 보조 스트림

4-1. DataInputStream

readInt(), readFloat(), readDouble() 등으로 기본 자료형을 읽는다.

try(DataInputStream dis = new DataInputStream(new FileInputStream("score.txt"))){
	while(true){
      	// 데이터를 읽어올 때, 반드시 순서대로 읽어와야 한다.
        // 그렇지 않으면 유의미 하지 않은 데이터를 읽어온다.
        System.out.println(dis.readUTF());
        System.out.println(dis.readInt());
        System.out.println(dis.readChar());
    }
}catch(EOFException e){
	/* read자료형() 메소드는 파일에서 더 이상 읽어올 값이 없는 경우
	EOFException (End Of File) 을 발생시킨다.*/
	System.out.println("파일 읽기가 완료 됐습니다");
}catch(IOException e){
	e.printStackTrace();
}

4-2. DataOutputStream

writeInt(), writeFloat(), writeDouble() 등으로 기본 자료형을 쓴다.

try(DataOutputStream dos = new DataOutputStream(new FileOutputStream("score.txt"))){
	dos.writeUTF("정유진");
	dos.writeInt(95);
	dos.writeChar('A');

	dos.writeUTF("홍길동");
	dos.writeInt(85);
	dos.writeChar('B');

	dos.writeUTF("이순신");
	dos.writeInt(75);
	dos.writeChar('C');

}catch (IOException e){
	e.printStackTrace();
}

5. 객체 보조 스트림


객체를 직렬화(Serialization)해 바이트 스트림으로 변환하거나, 반대로 바이트 스트림을 객체로 역직렬화(Deserialization)하는 데 사용되는 스트림

5-1. 직렬화와 역직렬화

(1) 직렬화
객체를 바이트 스트림으로 변화하는 과정을 의미한다.

(2) 역직렬화
바이트 스트림을 객체로 변화하는 과정을 의미한다.

(3) 클래스 직렬화

  • 객체의 입출력 처리를 위해서는 반드시 직렬화 처리를 진행해야 한다.
  • 이 때, 직렬화 대상 클래스에 Serializable 인터페이스만 구현하면 데이터 직렬화 처리가 가능하다.
  • transient는 직렬화에서 해당 필드를 제외하겠다는 의미의 키워드이다.
import java.io.Serializable;

public class Member implements Serializable {
    private String id;
    private String pwd;
    private transient int age;
    private char gender;

    public Member(String id, String pwd, int age, char gender) {
        this.id = id;
        this.pwd = pwd;
        this.age = age;
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Member{" +
                "id='" + id + '\'' +
                ", pwd='" + pwd + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                '}';
    }
}

age가 직렬화를 하지 않게 설정되어 있기 때문에, 그저 0으로만 출력되는 것을 확인할 수 있다.

5-2. ObjectInputStream

바이트 스트림을 객체로 역직렬화

try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("members.txt"))) {
	/* 반환형이 Object 이므로 사용할 타입으로 다운 캐스팅 */
	Member[] inputMembers =  (Member[]) ois.readObject();

	for(Member member : inputMembers) {
	System.out.println(member);
	}
} catch (IOException e) {
	e.printStackTrace();
} catch (ClassNotFoundException e) {
	/* 역직렬화 수행 시 해당 클래스가 존재하지 않을 경우 실패하므로
    ClassNotFoundException Handling이 필수 */
	e.printStackTrace();
}

5-3. ObjectOutputStream

객체를 바이트 스트림으로 직렬화

try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("members.txt"))) {
 	// 1. Member 타입의 객체를 하나씩 출력
  	// for(Member member : members) {
  	// 	 oos.writeObject(member);
  	// }

	// 2. Member[] 타입의 객체를 출력
	oos.writeObject(members);
} catch (IOException e) {
	e.printStackTrace();
}

6. 보조 스트림 정리


0개의 댓글