자바 I/O(Input/Output)
- java.io 패키지에 있는 클래스들의 모음
- 자바에서 각종 입출력을 담당
- Node(노드) : 자바에서 입출력을 수행하는 대상 => 입력노드 : 키보드, 마우스, 파일, 네트워크, 데이터베이스 등 => 출력노드 : 모니터, 스피커, 파일, 네트워크, 데이터베이스 등
Stream(스트림)
- 입력 또는 출력 데이터가 한 방향으로 끊임없이 전송 되는 것
- 출발지 노드 -> 도착지 노드
- 자바는 다양한 입출력 장치와 무관하고 일관성있게 프로그램을 구현할 수 있도록 일종의 가상 통로인 스트림을 제공
입력 스트림과 출력 스트림
- 입력 스트림
=> 자바에서 데이터가 입력될 때 처리하는 스트림
=> 예를 들어 어떤 동영상을 재생하기 위해 동영상 파일에서 자료를 읽을 때
=> FileInputStream, FileReader, BufferdInputStream, BufferedReader 등 - 출력 스트림
=> 자바에서 데이터가 출력될 때 처리하는 스트림
=> 예를 들어 편집 화면에서 사용자가 쓴 글을 파일에 저장할 때
=> FileOutputStram, FileWriter, BufferdOutputStream, BufferdWriter 등
바이트 단위 스트림과 문자 단위 스트림
- byte 기반(단위) 스트림
=> 그림, 사진, 영상 등 바이너리(Binary) 데이터를 입출력
=> InputStream, OutputStream을 최상위 클래스로 두고, XXXInputStream, XXXOutputStream 클래스가 하위클래스로 존재함 - char 기반(단위) 스트림
=> 문자 데이터(텍스트)를 입출력
=> Reader, Writer를 최상위 클래스로 두고 XXXReader, XXXWriter 클래스가 하위클래스로 존재함
기반 스트림과 보조 스트림
- 기반 스트림
=> 읽어들일 곳(소스)이나 써야할 곳(대상)에서 직접 읽고 쓸 수 있으며, 입출력 대상에 직접 연결되어 생성되는 스트림
=> FileInputStream, FileOutputStram, FileReader, FileWriter 등 - 보조 스트림
=> 직접 읽고 쓰는 기능은 없고, 항상 다른 스트림을 포함하여 생성됨
=> InputStramReader, OutputStreamWriter, BufferedInputStream, BufferedOutputStream 등
- 표준 입출력 : 컴퓨터에서 기본적으로 사용하는 입출력
=> 프로그램이 시작될 때 생성되므로 따로 만들 필요가 없음
=> 표준 입력장치 : 키보드
=> 표준 출력장치 : 모니터 - 표준 입출력을 담당하는 클래스 : System
=> System.in : 표준 입력을 담당(키보드에서 입력받기 가능)
=> System.out : 표준 출력을 담당(모니터로 출력 가능)
=> System.err : 모니터에 에러 정보 출력(잘 사용하지 않음)
바이트 단위 스트림(InputStream)
- 키보드로부터 데이터를 입력받아 처리하는 방법
- 1Byte 단위로 입력데이터를 처리
- read() 메서드를 사용하여 1Byte 만큼의 데이터를 가져올 수 있음
- 아무리 많은 데이터가 입력되어도 read() 메서드는 한 번에 1Byte만 처리할 수 있으므로 더 많은 데이터나 더 큰 단위 처리가 불가능
=> 영문 또는 숫자 등의 데이터 1글자만 처리 가능
=>한글이나 한자 등 2Byte(char 단위) 문자들은 처리 불가능
=> 읽어온 데이터가 int형이므로 문자로 변환 등의 후속 작업 필요 - 가장 저수준의 입력 방법
InputStream is = null;
// => finally 블록에서도 사용하기 위해 try 문 위쪽에 선언
try {
System.out.println("데이터를 입력하세요 : ");
is = System.in;
// => System.in 코드에 의해 키보드로부터 데이터 입력이 가능하며
// 입력스트림 객체를 InputStream 타입 변수에 저장(연결)
int n = is.read();
// => read() 메서드는 try~catch문을 사용하여 예외처리가 필수
// => 입력스트림 데이터 중 1Byte 만큼의 데이터를 읽어서 변수에 저장
System.out.println("입력데이터 : "+n); // 읽어온 1Byte 만큼의 데이터 출력
System.out.println("입력데이터를 문자로 변환 : "+(char)n); // 읽어온 1Byte 만큼의 데이터 출력
// => 추상메서드, 리턴타입이 int
} catch (IOException e) {
e.printStackTrace();
} finally {
if(is!=null)
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try ~ catch resources 구문을 사용하여 자원 반환(close())을 자동으로 수행
- 기본적으로 자원을 사용하는 객체(Connection, InputStream 등)는 사용 후 close() 메서드를 호출을 통해 사용중인 자원을 반환해야하며, 자원이 반환되지 않으면 반복적인 자원 요청으로 인해 자원이 고갈되어 더 이상 다른 사용자의 작업 요청을 수행할 수 없게 된다. => 예외 발생 여부와 관계없이 finally 블록 내에서 자원 반환 코드 기술
- try ~ with resources 구문은 try 문에서 반환할 자원을 갖는 객체를 생성하고, try ~ catch 블록이 끝나면 자동으로 자원을 반환해주도록함
기본 문법
try(자원을 반환할 객체 생성 및 변수에 저장) {
// 작업 수행
} catch(...) {
// 예외 처리 작업
}
try(InputStream is = System.in) {
System.out.println("데이터를 입력하세요 : ");
int n = is.read();
System.out.println("입력데이터 : "+n);
System.out.println("입력데이터를 문자로 변환 : "+(char)n);
} catch (IOException e) {
e.printStackTrace();
}
별도의 close() 메서드를 호출하지 않아도 자동으로 자원이 반환됨
반복문을 사용하여 1Byte씩 여러번 반복하여 입력 처리
System.out.println("데이터를 입력하세요. (취소시 (Ctrl+Z)");
try(InputStream is=System.in) {
int n = is.read();
// 반복문을 사용하여 더 이상 읽어 올 데이터가 없을 때(-1)까지 입력을 처리
while(n!=-1) {
// 읽어들인 1Byte 데이터(n)을 화면에 출력(문자로 변환)
System.out.println("입력데이터: "+n+", 문자로 변환: "+(char)n);
//다음 입력데이터 1Byte 가져오기
n=is.read();
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("입력 작업 종료!");
키보드로부터 데이터를 입력받아 처리하는 방법(2)
- InputStream 객체를 사용하여 1Byte 단위로 입력 데이터를 처리하고 않고 배열을 사용하여 한번에 여러 Byte 를 모아서 처리하는 방법
- read(byte[] b) 메서드를 호출하여 입력데이터를 배열크기만큼 읽어와서 저장
- 아무리 많은 데이터가 입력되어도 배열 크기만큼만 다룰 수 있기 때문에 더 많은 데이터나 더 큰 단위 처리가 불가능 => 영문 또는 숫자 등의 데이터 1글자만 처리 가능 => 한글이나 한자 등 2Byte(char 단위) 문자들은 처리 불가능 => 읽어 온 데이터를 문자로 변환하는 후속 작업 필요
- 저수준의 입력 방법
System.out.println("데이터를 입력하세요 : ");
try(InputStream is = System.in) {
// 1Byte 씩 묶음으로 처리할 byte[] 배열을 생성
byte[] bArr = new byte[10]; // 10Byte 단위로 묶을 경우
// read() 메서드 파라미터로 byte[] 배열을 값으로 사용
// 입력되는 스트림을 자동으로 배열 크기만큼 읽어서 배열에 저장
// => 배열에 저장된 데이터 크기(읽어들인 바이트 수)를 리턴
int n = is.read(bArr);
System.out.println("입력 데이터 크기 : " + n + "바이트");
// 반복문을 사용하여 배열(b)에 저장된 데이터를 출력
for(byte b : bArr) {
System.out.println("입력데이터 : " + b + ", 문자로 변환 : " + (char)b);
}
// String 클래스를 활용하면 byte[] 배열 데이터를 문자열로 변환 가능
String str = new String(bArr);
System.out.println("입력데이터(문자열) : " + str);
} catch(Exception e) {
e.printStackTrace();
}
이었던 데이터를 문자열로 바꿔준다면
System.out.println("데이터를 입력하세요 : (취소 시 Ctrl + Z)");
try(InputStream is = System.in) {
// 1Byte 씩 묶음으로 처리할 byte[] 배열을 생성
byte[] bArr = new byte[10]; // 10Byte 단위로 묶을 경우
int n = is.read(bArr);
while(n > 0) {
String str = new String(bArr);
System.out.println("입력데이터(문자열) : " + str);
n = is.read(bArr);
}
} catch(Exception e) {
e.printStackTrace();
}
System.out.println("입력 작업 종료!");
이렇게 표현할 수 있다.
키보드로부터 데이터를 입력받아 처리하는 방법(3)
- InputStreamReader 객체를 사용하여 char 단위로 입력데이터를 처리하는 방법
- InputStream 객체를 파라미터로 갖는 InputStreamReader 객체 생성 => 보조스트림을 사용하는 스트림 체이닝(Stream Chaining) 방식 문법 구성
- read() 메서드를 호출하여 입력데이터를 char단위(2Byte) 만큼 읽어와서 저장
- 아무리 많은 데이터가 입력되어도 2Byte(char) 만큼만 다룰 수 있기 때문에 더 많은 데이터나 더 큰 단위 처리가 불가능 => 영문 또는 숫자 등의 데이터 1글자 처리 가능 => 한글이나 한자 등 2Byte(char 단위) 문자도 처리 가능(1글자) => 읽어온 데이터를 문자로 변환하는 후속작업 필요
- InputStream 보다는 유용하지만, 여전히 낮은 수준의 입력 처리 방식
기본 문법
InputStreamReader reader = new InputStreamReader(InputStream 객체);
1. System.in 을 사용하여 입력스트림 가져오기
InputStream is = System.in;
2. InputStreamReader 객체 생성 => 파라미터 InputStream 객체를 전달
InputStreamReader reader = new InputStreamReader(is);
위의 문법을 한 문장으로 결합
InputStreamReader reader = new InputStreamReader(System.in);
System.out.println("데이터를 입력하세요 : ");
try(InputStreamReader reader = new InputStreamReader(System.in)) {
// InputStreamReader 객체의 read() 메서드를 호출하여 char 단위 읽어오기
int n = reader.read(); // char 단위 데이터 1개(1개 문자)를 int형으로 리턴
System.out.println("입력된 데이터 : " + n + ", 문자로 변환 : " + (char)n);
} catch(IOException e) {
e.printStackTrace();
}
System.out.println("데이터를 입력하세요 : (Ctrl + Z)");
try(InputStreamReader reader = new InputStreamReader(System.in)) {
// InputStreamReader 객체의 read() 메서드를 호출하여 char 단위 읽어오기
int n = reader.read(); // char 단위 데이터 1개(1개 문자)를 int형으로 리턴
while(n != -1) {
System.out.println("입력된 데이터 : " + n + ", 문자로 변환 : " + (char)n);
n = reader.read();
}
} catch(IOException e) {
e.printStackTrace();
}
System.out.println("입력 종료!");
키보드로부터 데이터를 입력받아 처리하는 방법(4)
- InputStreamReader 객체를 사용하여 char 단위로 읽어 온 데이터를 배열을 사용하여 한 번에 여러 문자로 모아서 처리하는 방법
System.out.println("데이터를 입력하세요 : ");
try(InputStreamReader reader = new InputStreamReader(System.in)) {
// 여러 개의 char 단위 데이터를 저장할 char[] 배열 생성
char[] chArr = new char[10];
int n = reader.read(chArr);
System.out.println("입력데이터(문자열) : " + new String(chArr));
} catch(IOException e) {
e.printStackTrace();
}
키보드로부터 데이터를 입력받아 처리하는 방법(5)
- BufferedReader 객체를 사용하여 String 단위로 입력 데이터를 처리하는 방법
- InputStream 객체를 파라미터로 갖는 InputStreamReader 객체 생성 후 다시 InputStreamReader 객체를 파라미터로 갖는 BufferedReader 객체를 생성 => 보조스트림을 사용하는 스트림 체이닝(Stream Chaining) 방식 문법 구성 => 이처럼 기본스트림을 꾸며주는 역할을 하는 보조스트림을 적용하여 입출력을 처리하는 방식을 데코레이션 패턴(Decoration Pattern) 이라고 함
- read() 메서드가 아닌 readLine() 메서드를 사용하여 String 단위로 처리 => 즉, 데이터를 한 문장(라인 = 엔터키 기준) 단위로 읽어들여 처리
- 키보드를 통해 입력되는 데이터를 처리하는 최종적인 방법(가장 효율적)
스트림 체이닝을 통한 데코레이션 패턴 구현
- 기본 입력스트림 객체(InputStream) 생성 = byte 단위 처리
InputStream is = System.in;
2. 입력스트림을 연결하는 보조스트림 InputStreamReader 객체 생성 = char 단위 처리
InputStreamReader reader = new InputStreamReader(is);
3. 향상된 입력 보조스트림 BufferedReader 객체 생성 = String 단위 처리
BufferedReader buffer = new BufferedReader(reader);
위 세문장을 하나의 문장으로 결합
BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
System.out.println("데이터를 입력하세요 : ");
try(BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in))) {
// 입력스트림에서 한 줄의 데이터(문자열) 읽어오기
String str = buffer.readLine();
System.out.println("입력데이터 : " + str);
} catch(IOException e) {
e.printStackTrace();
}
반복문을 사용하여 Ctrl + Z 입력 시 까지의 모든 문자열을 출력
주의! Ctrl + Z 입력 데이터가 정수일 때는 -1, 문자열일 때는 null 값 사용
System.out.println("데이터를 입력하세요 : ");
try(BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in))) {
// 입력스트림에서 한 줄의 데이터(문자열) 읽어오기
String str = buffer.readLine();
while(str != null) { // 입력 데이터가 존재할 동안 반복
System.out.println("입력데이터 : " + str);
str = buffer.readLine(); // 다음 한 줄 다시 읽어오기
}
} catch(IOException e) {
e.printStackTrace();
}
System.out.println("입력 종료!");
'JAVA' 카테고리의 다른 글
[JAVA] 자바의 기본 데이터 입출력 (0) | 2023.12.07 |
---|---|
[JAVA] 자바 I/O - 모니터로부터 데이터를 출력하는 방법 2가지 (0) | 2023.12.07 |
[JAVA] 쓰레드를 일시 정지 상태로 만드는 방법 (1) | 2023.11.28 |
[JAVA] 쓰레드의 우선순위 (2) | 2023.11.28 |
[JAVA] 멀티쓰레딩 구현 코드의 변형 (1) | 2023.11.28 |