JAVA의 입출력
입력이란??
- 외부에서 받은 데이터를 프로그램 내부 공간인 메모리로 옮기는 행위
콘솔을 통해 입력받은 모든 데이터는 System.in(Standard input buffer)이라는 공간으로 들어오고 이 버퍼를 적당한 양식으로 데이터를 절단하여 프로그램 내의 지정한 메모리상의 위치로 옮기게 되는 것이다
- 1) Scanner
- 공란과 개행으로 입력값의 경계를 결정한다.
- 입력받은 즉시 자료형이 확정되며, 자체적으로 Exception이 처리가 가능하게 정의되어 있는 클래스이다.
- 입력받고 바로 메모리에 전달하는 방식이다
- 장점 : 사용이 편리
- 단점 : 처리시간이 상대적으로 길다.
1 2 3 4 5 6 7 8 9 10 11
import java.util.Scanner; // Scanner 클래스를 import 해줘야 사용 가능. public class Main{ public static void main(String[] args){ Scnnaer sc = new Scanner(System.in); String s = sc.nextLine(); int i = sc.nextInt(); } }
- 2) BufferedReader
- 이 클래스는 버퍼를 이용하는 대표적인 input/output 클래스이다.
- 라인 단위로 입력을 받는다. 즉 개행이 입력값의 경계를 결정한다. 그렇기 때문에 한줄에 공란을 기준으로 여러 값들을 입력했다면 split을 해주어야 한다.
- Scanner와 달리 Exception이 없기 때문에 throws IOException을 해주어야 한다.
- 입력된 데이터를 바로 메모리에 전달하는게 아니라 버퍼에 저장해 두었다가 전달한다.
- 장점 : 처리시간이 빠르다
- 단점 : 모든 입력값은 String 형태로 인식하므로 필요한 자료형으로 변환이 필요하다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
import java.io.*; public class Main{ public static void main(String[] args) throws IOException{ InputStream is = System.in; // byte stream, 입력받는 스트림 InputStreamReader isr = new InputStreamReader(is); // byte stream을 문자 stream으로 정리 BufferedReader br = new BufferedReader(isr); // 문자 stream 을 다시 정리하여 문자열 stream으로 String s = br.readLine(); // 만약 받은 데이터를 정수형으로 처리하고 싶다면.. int i = Integer.parseInt(br.readLine()); } } // 입력 받은 값을 공백을 기준으로 자동으로 분리해준다 StringTokenizer st = new StringTokenizer(br.readLine()); // "JAVA 공부 열심히 하자" String s1 = st.nextToken(); -> "JAVA" String s2 = st.nextToken(); -> "공부" String s3 = st.nextToken(); -> "열심히" String s4 = st.nextToken(); -> "하자"
비교
Sanner는 편리성 대신 처리속도의 지연
BufferedReader는 처리속도가 빠른 대신에 코드의 불편함이 있다.
i n p u t 이라는 단어를 입력 받는다고 한다면,
Scanner의 경우 i 입력받고 공란과 개행을 입력값의 경계로 하기 때문에 i를 메모리에 올리고 n 을 입력받고 메모리에 올리고를 반복하게 된다. 메모리에 올리는 과정에서 시간이 지연된다.
BufferedReader의 경우 버퍼에다가 i”공란”n”공란”p”공란”.. 식으로 입력값을 받다가 개행을 만나게 되면 i n p u t을 한 번에 메모리에 올리게 된다. 그러므로 처리속도는 빠르지만 입력값을 가공하는 코드를 입력해주어야 한다
출력이란??
- 출력은 메모리에 있는 데이터를 출력 스트림에 쏟아내고 스트림을 통해 화면에 랜더링되는 방식이다.
- 이 때, 데이터를 쏟아내는 행위(flush)의 시간 소모가 크다.
- 2가지의 시간 소모 부담 요소가 존재한다
- 데이터를 쏟아내는 방식
- 출력 스트림에 접근하는 방식
- 1) StringBuilder
- StringBuilder 클래스는 메모리에서 문자열을 만들어 가다가 한 번에 쏟아내어 랜더링 하는 방식이다. 즉, 문자열 데이터를 메모리 상에서 빌드업하는 역할을 수행한다.
- output을 출력한다고 했을 때, “o” “u” ”t” ”p” ”u” ”t”을 쏟아내는 것과 “output”을 한 번에 출력하는 것에는 효율적인 차이가 있다. 6번의 flush가 아니라 1번의 flush를 수행하게 되는 것이다.
- 이처럼 데이터를 메모리 상에 빌드하고 출력하는 것이 StringBuilder라고 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); StringBuilder sb = new StringBuilder(); for(int i = 0; i < 3; i++){ String line = sc.nextLine(); // "java" enter "공부" enter "화이팅" enter sb.append(line + '\n'); } System.out.print(sb); } } // 출력 결과 // java // 공부 // 화이팅 => for문에서 3번의 print를 수행하지 않고 StringBuilder를 이용하여 메모리에 빌드하였다가 한번에 출력하였다. String res = null; for(int i = 0; i < 3; i++){ String line = sc.nextLine(); // "java" enter "공부" enter "화이팅" enter res += line + "\n"; } System.out.print(res); String으로 합치는 것과 StrinBuilder를 사용하는 것의 차이 1) 성능 - String의 경우 문자열을 더할 때마다 새로운 객체를 생성 - StrinBuilder는 새로운 객체를 생성하지 않고 기존의 객체에 내용을 수정하여 문자열을 추가한다 2) 메모리 - String의 경우 불변 객체이므로 문자열이 추가될 때마다 새로운 객체가 생성 - StrinBuilder는 가변 객체이므로 문자열이 추가될 때마다 필요에 따라 동적으로 크기가 조절된다 - 가변?불변? -> 객체의 내부 상태를 변경할 수 있는지에 대한 유무. 즉, 객체의 내부 데 이터를 수정하거나 추가가 할 수 있는지의 유무
- 2) BufferedWriter
- 위에서 설명한 BufferedReader랑 같은 개념이고 입력대신 출력으로 바뀐것이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
import java.io.*; import java.util.Scanner; public class Main{ public static void main(String[] args) throws IOException{ OutputStream os = System.out; // byte stream, 출력 스트림 OutputStreamWriter osw = new OutputStreamWriter(os); // byte stream을 문자 stream으로 정리 BufferedWriter bw = new BufferedWriter(osw); // 문자 stream 을 다시 정리하여 문자열 stream으로 Scanner sc = new Scanner(System.in); for(int i = 0; i < 2; i++){ String line = sc.nextLine(); bw.write(line + '\n'); } bw.flush(); bw.close(); } }
스트림??
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
🔸Byte 스트림 (Byte Stream)
- 8 비트 단위로 데이터를 처리하는 스트림
- InputStream, OutputStream
- 이진 데이터(이미지, 오디오 등)를 처리할 때 주로 사용
- 텍스트 데이터를 처리할 때도 사용할 수 있지만 텍스트 인코딩과 관련하여 문자 인코딩 문제가 발생할 수 있다고 한다.
🔸문자 스트림 (Character Stream)
- 문자 스트림은 문자 단위로 데이터를 처리하는 스트림
- Reader와 Writer 클래스를 기반으로 한다.
- 텍스트 데이터를 처리하는데 최적화 되어 있으며, 문자 인코딩을 자동으로 처리하여 문자열 데이터를 읽고 쓰는데 유용하다.
- 문자 인코딩을 자동으로 처리
🔸문자열 스트림 (String Stream)
- 문자열을 다루는 스트림
- String 클래스의 메서드를 이용하여 문자열을 읽고 쓰는 작업을 지원
- StringReader와 StringWriter 클래스를 사용하여 문자열을 읽고 쓰는 기능을 제공