입출력을 뜻하는 것으로, 입력은 키보드, 네트워크, 파일 등으로부터 받을 수 있고, 출력은 화면, 네트워크, 파일 등에 할 수 있다.
Java I/O에서 사용되는 객체는 자바에서 사용되는 객체이다. 즉, Java I/O가 제공하는 객체는 어떤 대상으로부터 읽어들여서 어떤 대상에게 쓰는 일을 한다.
또한 Java I/O는 조립되어 사용되도록 만들어졌다. 즉, 아래와 같이 Decorator 패턴으로 만들어졌다.
장식할 대상을 주인공으로 보고 이 주인공을 장식한다고 하자. 케이크의 빵이 주인공이라고 하면, 이 빵에 크림과 딸기 등의 장식을 덧붙일 수 있다. 위 그림에서 보면 ConcreteComponent가 주인공이고, Decorator가 장식인데, Decorator는 Component를 가질 수 있다. 즉 컴포넌트를 상속받는 것들도 가질 수 있다는 말이다.
여기서 Component 역할을 수행하는 것이 InputStream, OutputStream, Reader, Writer이고, 추상 클래스이다. 그리고 장식(Decorator)은 이 InputStream, OutputStream, Reader, Writer를 생성자에서 받아들인다. 반면에 주인공(ConcreteComponent)는 어떤 대상에게서 읽어들일지, 쓸지를 결정한다.
즉, 주인공은 1byte, byte[], 1char, char[] 단위로 읽고 쓰는 메서드를 가진다. 하지만 장식은 다양한 방식으로 읽고 쓰는 메서드를 가진다.
Java I/O의 특수한 객체
- System.in : 표준 입력(InputStream)
- System.out : 표준 출력(PrintStream)
- System.err : 표준 에러 출력(PrintStream)
Java I/O의 클래스 상속도
위 그림에서 InputStream, OutputStream, Reader, Writer가 추상 클래스이고, 이를 상속 받는 클래스들 중에서 주인공 역할을 수행하는 클래스와 장식 역할을 수행하는 클래스가 있다.
Java I/O 클래스는 이름이 중요하다.
- Stream으로 끝나는 클래스 : byte 단위 입출력 클래스
- InputStream으로 끝나는 클래스 : byte 단위로 입력을 받는 클래스
- OutputStream으로 끝나는 클래스 : byte 단위로 출력을 하는 클래스
- Reader로 끝나는 클래스 : 문자 단위로 입력을 받는 클래스
- Writer로 끝나는 클래스 : 문자 단위로 출력을 하는 클래스
- File로 시작할 경우(File 클래스 제외) : File로부터 입력이나 출력을 하는 클래스
- ByteArray로 시작할 경우 : 입력 클래스의 경우 byte[]로부터 읽어들이고, 출력 클래스의 경우 클래스 내부의 자료구조에 출력을 한 후 출력된 결과를 byte[]로 반환하는 기능을 가진다.
- CharArray로 시작할 경우: char[]로 입출력하는 클래스
- Filter로 시작할 경우 : Filter로 시작하는 입출력 클래스의 경우는 직접 사용하는 것보다는 상속을 받아 사용을 하며, 사용자가 원하는 내용만 필터링할 목적으로 사용된다.
- Data로 시작할 경우 : 다양한 데이터 형을 입출력할 목적으로 사용한다. 특히 기본형 값(int, float, double 등)을 출력하는데 유리하다.
- Buffered로 시작할 경우 : 클래스에 내부에 메모리를 가지고 있다. 즉, 프로그램에서 Buffer라는 말은 메모리를 의미하며, 입출력 시에 병목현상을 줄이고 싶을 경우에 사용한다.
- RandomAccessFile : 입출력을 모두 할 수 있는 클래스로써 파일에서 임의의 위치의 내용을 읽거나 쓸 수 있는 기능을 제공한다.
Java I/O 클래스는 생성자가 중요하다.
상속관계가와 생성자가 중요하다.
장식은 InputStream, OutputStream, Reader, Writer를 생성자에서 받아들인다.
https://docs.oracle.com/javase/8/docs/api/index.html?java/io/package-summary.html
여기서 ByteArrayInputStream은 생성자에서 InputStream을 받아들이지 않으므로 주인공 역할이다. 즉, 어디서 읽어들일건지, 어디에 쓸 건지를 결정하는 클래스이다. 따라서 이 클래스는 byte[]에서 읽어들이기 위한 클래스인 것이다.
- StringWriter는 Writer를 상속받는 주인공 클래스이다.
- PrintStream은 장식이다.
PrintStream(OutputStream out)
Creates a new print stream.
|
PrintStream(OutputStream out, boolean autoFlush)
Creates a new print stream.
|
PrintStream(OutputStream out, boolean autoFlush, String encoding)
Creates a new print stream.
|
- FileInputStream은 주인공이다.
- ConstructorsConstructor and Description
FileInputStream(File file) Creates a FileInputStream by opening a connection to an actual file, the file named by the File object file in the file system.FileInputStream(FileDescriptor fdObj) Creates a FileInputStream by using the file descriptor fdObj, which represents an existing connection to an actual file in the file system.FileInputStream(String name) Creates a FileInputStream by opening a connection to an actual file, the file named by the path name name in the file system. - FileReader도 주인공이다.
- ConstructorsConstructor and Description
FileReader(File file) Creates a new FileReader, given the File to read from.FileReader(FileDescriptor fd) Creates a new FileReader, given the FileDescriptor to read from.FileReader(String fileName) Creates a new FileReader, given the name of the file to read from. - File은 decorator 패턴에 적용되지 않는 그냥 Java I/O에서 File클래스이다. 즉, 읽고 쓰기 위한 클래스가 아니다.
Class File
- java.lang.Object
- java.io.File
- PipedInputStream은 주인공, 장식 역할 모두 가능하다.
Class PipedInputStream
- java.lang.Object
- java.io.InputStream
- java.io.PipedInputStream
- java.io.InputStream
PipedInputStream() |
PipedInputStream(int pipeSize)
Creates a PipedInputStream so that it is not yet connected and uses the specified pipe size for the pipe's buffer.
|
PipedInputStream(PipedOutputStream src)
Creates a PipedInputStream so that it is connected to the piped output stream src.
|
PipedInputStream(PipedOutputStream src, int pipeSize)
Creates a PipedInputStream so that it is connected to the piped output stream src and uses the specified pipe size for the pipe's buffer.
|
Java I/O를 잘 다루려면 API를 한번쯤은 읽어봐야 한다.
그렇다면 키보드로부터 한 줄씩 입력받아 화면에 한 줄씩 출력하라는 문제를 해결하려면 어떻게 해야할까?
키보드로부터 입력받는 것은 byte 입력일까? char입력일까? 답은 char 단위 입출력이다. 그리고 char단위 입출력 클래스는 Reader, Writer이다.
이때, BufferedReader라는 클래스는 readLine이라는 한줄을 읽는 메서드를 가지고있으며, 더이상 읽어들일게 없으면 null을 반환한다.
readLine
public String readLine()
throws IOException
Direct Known Subclasses:BufferedReader, CharArrayReader, FilterReader, InputStreamReader, PipedReader, StringReader
- 이 중 CharArryaReader를 보면 주인공인데, char[] 로부터 읽어들이는 클래스이다. 따라서 우리는 키보드로부터 읽어들여야 하는데 이 클래스는 문자로부터 읽어들이므로 후보로써 탈락이다.
- FilterReader는 생성자에서 Reader를 또 받아들이고 있으므로 탈락이다.
- InputStreamReader는 생성자에서 InputStream을 받아들이는 장식이고, 우리가 가지고 있는 System.in이고 이는 InputStream 타입이다.
따라서 다음과 같이 코드가 작성될 수 있다.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println("읽어들인값 = " + line);
}
그럼 다음과 같은 결과를 확인할 수 있고, 더이상 키보드로 읽어들일게 없다면 Command + D를 누르면 nul값을 키보드로 전달할 수 있다.(End Of File - EOF)
hi
읽어들인값 = hi
12345
읽어들인값 = 12345
hello world
읽어들인값 = hello world
^D
이렇게해서 키보드로부터 한줄씩 입력받아 한줄씩 출력하는 코드를 작성할 수 있다.
- Device Buffer : 운영체제 buffer. Enter 입력전까지 입력 후에는 자바 프로그램에 전달
- System.in : 내가 입력한 값을 System.in이 읽어들이고
- 입력한 값이 InputStreamReader에게 전달하고
- 이 값을 다시 BufferedReader에게 전달하고
- BufferedReader는 문자열로 Return한다.
인용
'Language > Java' 카테고리의 다른 글
Java I/O - IO Stream (0) | 2023.09.18 |
---|---|
I/O - File 클래스 (0) | 2023.09.18 |
제네릭과 컬렉션 프레임워크 (0) | 2023.09.16 |
배열 (0) | 2023.09.16 |
익명 클래스 (Anonymous Class) (0) | 2023.09.15 |