- Input & Output, 즉 입출력
- 입력은 키보드, 네트워크, 파일 등으로부터 받을 수 있다.
- 출력은 화면, 네트워크, 파일 등에 할 수 있다.
Java IO도 객체다.
- Java IO에서 사용되는 객체는 자바 객체이다.
- Java IO에서 제공하는 객체는 어떤 대상으로부터 읽어들여 어떤 대상에게 쓰는 일을 한다.
Decorator 패턴
Decorator 패턴: 장식 패턴, 장식할 대상이 있다.
- 장식할 대상(주인공): ConcreteComponent
- 장식: Decorator
- 마름모 화살표: Decorator는 Component를 가질 수 있다.
- Decorator의 필드에 Component를 포함한다는 의미임: 생성자에 초기화가 포함됨
- Component를 상속받는 것들도 가질 수 있다.
Java IO는 여러 부분을 조립하여 사용한다.
- Component(장식 대상, 주인공): InputStream, OutputStream, Reader, Writer
- 어떤 대상에게서 읽어들일지, 쓸지를 결정한다.
- 1byte or byte[] 단위로 읽고 쓰는 메서드를 가진다.
- 1char or char[] 단위로 읽고 쓰는 메서드를 가진다.
- Decorator(장식)
- 장식은 InputStream, OutputStream, Reader, Writer(Component = 장식 대상, 주인공)를 생성자에서 인자로 받는다
- 이들이 Component이므로 Decorator 생성자 클래스에서 인자로 받는다.
- 추상 클래스이므로 new로 객체 생성할 수 없음
- 장식은 다양한 방식으로 읽고 쓰는 메서드를 가진다.
- 장식은 InputStream, OutputStream, Reader, Writer(Component = 장식 대상, 주인공)를 생성자에서 인자로 받는다
- Java IO에서 무엇이 component고 무엇이 decorator인지 구분할 수 있어야 한다.
Java IO의 특수한 개체
- System.in: 표준 입력(InputStream), 키보드로부터 입력
- System.out: 표준 출력(PrintStream), 화면에 출력
- System.err: 표준 에러 출력(PrintStream), 화면에 에러 출력
Java IO 클래스 상속도
- 사실 UML 상에서 상속을 나타내기 위해서 상속을 하는 Object 방향에 삼각형 화살표 가 있어야 한다.
클래스 이름 | 설명 |
---|---|
Stream으로 끝나는 클래스 | byte 단위 입출력 클래스 |
InputStream으로 끝나는 클래스 | byte 단위로 입력을 받는 클래스 |
OutputStream으로 끝나는 클래스 | byte 단위로 출력을 하는 클래스 |
Reader로 끝나는 클래스 | 문자 단위로 입력을 받는 클래스 |
Writer로 끝나는 클래스 | 문자 단위로 출력을 하는 클래스 |
File로 시작할 경우(File 클래스 제외) | File로부터 입력이나 출력을 하는 클래스 |
ByteArray로 시작할 경우 | 입력 클래스의 경우 byte 배열로부터 읽어들이고, 출력 클래스의 경우 클래스의 내부의 자료구조에 출력을 한 후 출력된 결과를 byte 배열로 반환하는 기능을 가진다. |
CharArray로 시작할 경우 | 입력 클래스의 경우 char 배열로부터 읽어들이고, 출력 클래스의 경우 클래스 내부의 자료구조에 출력을 한 후 출력된 결과를 char 배열로 반환하는 기능을 가진다. |
Filter로 시작할 경우 | Filter로 시작하는 입출력 클래스는 직접 사용하는 것보다 상속받아 사용하며, 사용자가 원하는 내용만 필터링할 목적으로 사용된다. |
Data로 시작할 경우 | 다양한 데이터형을 입출력할 목적으로 사용한다. 특히 기본형 값(int, float, double 등)을 출력하는데 유리하다. |
Buffered로 시작할 경우 | 프로그램에서 Buffer라는 말은 메모리를 의미한다. 입출력 시에 병목현상을 줄이고 싶을 경우 사용한다. |
RandomAccessFile | 입력이나 출력을 모두 할 수 있는 클래스로서, 파일에서 임의의 위치의 내용을 읽거나 쓸 수 있는 기능을 제공한다. |
생성자/상속관계가 중요하다.
- 생성자의 인자로 무엇을 받는지가 component와 decorator를 구분하는 방법임.
- Class ByteArrayInputStream
- InputStream을 상속받고 있음
- 생성자가 인자로 InputStream, OutputStream, Reader, Writer를 받지 않음: 이 클래스는 주인공임
- byte[] 로부터 읽어들이기 위한 클래스
- Clas BufferedInputStream
- InputStream을 상속받고 있음
- 생상자 인자가 InputStream임: 이 클래스는 장식임
- Class File
- Decorator도 아니고, component도 아님
- Class PipedInputStream
- byte[]를 받으므로 Component 임
- 하지만 생성자 중 하나에서 인자로 받는 PipedOutputStream을 들어가보면 이 클래스는 OutputStream을 상속받고 있다. 그래서 이 클래스는 Decorator로 보기도 함.
예제
Java IO를 잘 다루기 위해서는 API를 꼭 읽어봐야 한다.✨✨✨
키보드로부터 한 줄씩 입력받아 화면에 한 줄씩 출력하시오
이 문제를 해결하려면 어떻게 해야할까?
public class KeyboardIOExample {
public static void main(String[] args) throws Exception {
// 모든 예외는 편의를 위해 그냥 JVM이 처리하도록 던져버림
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 3. 생성자가 알맞게 초기화하도록 완성한다.
String line = null;
while((line = br.readLine()) != null) {
// 2. readLine 메서드는 더이상 입력이 없다면 null을 반환한다.
// 프로그램 실행 시 cmd + d/ctrl + d를 눌러 null 값이 들어가게 할 수 있음(키보드로부터 EOF, end of file 정보, 즉 더이상 읽을 것이 없다는 것을 전달함)
System.out.println("읽어들인 값: " + line);
}
}
}
1. 문제 분석
- 키보드: System.in (InputStream, 주인공: component, 어디에서 읽을 것인지)
- 화면 출력: System.out (PrintStream, 주인공: component, 어디에서 쓸 것인지)
- 키보드로 입력받는다면 문자를 입력받는다: char 단위 입출력
- char 단위 입출력 클래스는 Reader, Writer
2. 필요한 메서드 찾기
- 한 줄 읽기: BufferedReader클래스는 readLine이라는 메서드를 가지고 있더라
- 더이상 읽을 것이 없다면 null을 반환: While문을 추가하였다.
- decorator 이다
- 한 줄 쓰기: PrintStream, PrintWriter
3. 생성자 완성하기
BufferedReader()
는 빈 생성자가 없음: Reader형 자료를 인자로 받는다(decorator).- Reader는 추상 클래스이므로 이 클래스의 자식 클래스를 인자로 받게 해야 한다.
- 무엇으로부터 입력받는지 결정하는 것이다: 키보드로부터 입력받는 클래스를 찾아보자
- Class Reader에서 보듯이, direct know subclass들 중 하나가 들어가야 할 것.
BufferedReader
: 사용 클래스이므로 이 클래스는 아닐 것CharArrayReader
: char[]를 받는 component로, 문자로부터 입력받는다.FilterReader
: 또 Reader를 받아야InputStreamReader
: InputStream을 받는 decorator 클래스, InputStream은 키보드로부터 받는 입력이므로 이 클래스를 사용할 수 있다.
(간단히) 무슨일이 일어나나?
참고 자료: Reading data From keyboard, Java T point
- Device buffer는 운영체제가 관리한다: 키보드로 콘솔에 입력하여 엔터를 치지 않은 상태에 여기에 저장되어 있음
- Device buffer를 System.in이 받아들인다.
- 버퍼에 있는 값을 BufferedReader가 한 줄씩 입력받아 자바 프로그램에 전달해 준다.
- 좀 더 내부적인 작동은 다음 글에.