Post

[자바]콘솔 입출력

JAVA

콘솔 입력

자바 코드에서 입력한 문자열을 얻기위해서는 자바의 System.in 을 사용한다

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.io.IOException;
import java.io.InputStream;

public class Sample {
    public static void main(String[] args) throws IOException {
        InputStream in = System.in;

        int a;
        a = in.read();

        System.out.println(a);
    }
}

InputStream 은 자바의 내장 클래스이다. 자바의 내장 클래스중에 java.lang 패키지에 속해 있지 않은 클래스는 위 코드처럼 필요할 때 항상 improt 해서 사용해야한다.

System이나 String 등의 클래스는 java.lang 패키지에 속해 있는 클래스이므로 별도의 import 과정이 필요없다

System.inInputStram 의 객체 이다. System.in을 사용하게 되면 콘솔창에서 입력 값을 받을 수 있다.

InputStream에는 1byte의 사용자 입력값을 읽을 수 있는 read라는 메소드가 있다. read 메소드로 읽은 데이터는 byte자료형으로 저장되는 것이 아니라 int 자료형으로 저장된다. 만약 a를 입력했다면 a에 해당되는 아스키코드값인 97이 출력되게 된다.

🙋그렇다면 만약 한글자가 아닌 abc를 입력하면 어떻게 될까?

이번에도 마찬가지로 97이 출력되게 된다. 그이유는 InputStream의 read 메소드는 1 byte만 읽기 때문이다. 즉, 사용자는 “abc”라는 3 byte의 데이터를 전달했지만 프로그램에서는 처음 1 byte만 읽게 된다. 이렇게 입력된 데이터를 입력 스트림(Stram)이라고 한다. 스트림은 이어져 있는 데이터(byte)의 형태를 의미한다.

점프투 자바 💡 스트림(Stream) 이란? 스트림을 가장 쉽게 이해하려면 수도꼭지를 생각하면 된다. 수도꼭지를 틀면 물이 나오고 수도꼭지를 잠그면 물이 나오지 않는다. A라는 곳에서부터 B라는 곳까지 수도관이 연결되어 있고 A에서 계속 물을 보낸다면 B에서 수도꼭지를 틀때마다 물이 나오게 될 것이다. 여기서 스트림은 A수도관에서 B수도관으로 이동하는 물의 흐름이라고 할 수 있다. 프로그래밍에서는 다음과 같은 것들을 스트림이라고 할 수 있다. - 파일 데이터 (파일은 그 시작과 끝이 있는 데이터의 스트림이다.) - HTTP 송수신 데이터 (브라우저가 요청하고 서버가 응답하는 HTTP 형태의 데이터도 스트림이다.) - 키보드 입력 (사용자가 키보드로 입력하는 문자열은 스트림이다.)

🤷그렇다면 사용자가 3byte를 입력했을 때 3 byte를 전부 읽고싶다면 어떻게 해야할까?

길이 3짜리 byte 배열을 만든후 read 메소드 입력값으로 전달하면 콘솔 입력이 해당 배열에 저장이 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.io.IOException;
import java.io.InputStream;

public class Sample {
    public static void main(String[] args) throws IOException {
        InputStream in = System.in;

        byte[] a = new byte[3];
        in.read(a);

        System.out.println(a[0]);
        System.out.println(a[1]);
        System.out.println(a[2]);
    }
}
1
2
3
4
abc (입력)
97 (출력)
98 (출력)
99 (출력)

👉번외로 여기서 아무런 입력값도 입력하지 않고 엔터를 누르게되면 0이 3번 출력될거 같은데

1
2
3
4
13 (출력)
10 (출력)
0 (출력)

예상했던것과 달리 위와 같이 출력된다. 그 이유는 개행문자, 즉 컴퓨터에서 줄바꿈을 나타내는 제어 문자때문에 일어난일이다. Java에서 줄바꿈을 인식하는 문자 \n 와 커서의 위치를 맨앞으로 옮기는 \r 이 합쳐져서 이둘의 아스키 코드 값이 출력되게 된것이다.

InputStreamReader

하지만 읽어들인 값을 항상 아스키코드 값으로 해석해야 하는 방식은 여전히 불편하다.

🙋‍♂️입력한 문자값을 그대로 출력해 볼 수 없을까?

바이트 대신 문자로 입력 스트림을 읽으려면 InputStreamReader 를 사용하면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Sample {
    public static void main(String[] args) throws IOException {
        InputStream in = System.in;
        InputStreamReader reader = new InputStreamReader(in);
        char[] a = new char[3];
        reader.read(a);  //char의 배열은 String과 같다

        System.out.println(a);
    }
}

InputStreamReader를 사용하기 위해 import 문이 하나 더 추가되었다. 그리고 InputStreamReader 객체를 생성할 때는 다음과 같이 생성자의 입력으로 InputStream 객체인 System.in이 필요하다.

1
InputStreamReader reader = new InputStreamReader(System.in);

이전에는 읽어들일 값을 byte배열로 선언했는데 InputStreamReader를 이용하면 다음처럼 byte 대신 char 배열을 사용할 수 있다.

🙋‍♂️그냥 char로 형변환을 사용하면 되지 굳이 InputStreamReader가 필요할까?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package Test;

import java.io.IOException;
import java.io.InputStream;

public class Sample {
    public static void main(String[] args) throws IOException {
        InputStream in = System.in;

        byte[] a = new byte[3];
        in.read(a);
        
        char[] b = new char[3];
        for(int i=0; b.length >i; i++) {
        	b[i] = (char)a[i];
        }
        System.out.println(b);

    }
}
1
2
abc (입력)
abc (출력)

원했던 결과 대로 잘 출력 되는 것을 볼 수 있다 하지만 한글을 사용하게된다면

1
2
안녕 (입력)
???  (출력)

한글이 깨지게된다. 그 이유는 맨처음 말했던거 처럼 InputStram은 1byte씩 사용자 입력값을 읽게되는데 한글은 2byte가 묶여서 한글자가 되기 때문에 한글대신 ?가 출력되게 된것이다. InputStreamReader는 이러한 문제점을 해결해 준다.

BufferedReader

프로그램이 많이 개선되었지만 여전히 고정된 길이로만 스트림을 읽게 된다.

🤷‍♂️반복문을 사용하지않고 사용자가 엔터키를 입력할 때까지 사용자의 입력을 전부 받아들일 수 없을까?

BufferedReader 를 이용하면 가능하다!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Sample {
    public static void main(String[] args) throws IOException {
        InputStream in = System.in;
        InputStreamReader reader = new InputStreamReader(in);
        BufferedReader br = new BufferedReader(reader);

        String a = br.readLine();
        System.out.println(a);
    }
}

BufferedReader는 객체 생성시 생성자의 입력값으로 InputStreamReader의 객체가 필요하다. BufferedReader의 readLine메소드를 이용하면 사용자가 엔터키를 입력할 때까지 입력했던 모든 문자열을 읽을 수 있다.

1
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  • 한줄로 표현이 가능하다

총정리

  • InputStream - byte
  • InputStreamReader - character
  • BufferedReader - String

Scanner

J2SE 5.0 부터 Scanner 라는 java.util.Scanner 클래스가 새로 추가되었다. Scanner 클래스를 이용하면 콘솔입력을 훨씬 쉽게 사용할 수 있다.

1
2
3
4
5
6
7
8
import java.util.Scanner;

public class Sample {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println(sc.next());
    }
}
  • Scanner를 사용하기 위해서 먼저 java.util.Scanner 클래스를 import 해야한다.

Scanner 클래스는 생성자의 입력으로 System.in 을 필요로 한다.

Scanner 객체의 next() 메소드는 단어 하나를 읽어들인다. 문자열을 읽어 들일려면 nextLine 숫자를 읽어 들일려면 nextInt를 사용하면된다.

총정리

  • next - 단어
  • nextLine - 라인
  • nextInt - 정수

콘솔 출력

지금까지 System.out.println 메서드를 계속해서 사용해 왔다. System.out 은 PrintStream 클래스의 객체이다. 동일한 역할을 하는 객체로 System.err 도 있다. 다만 System.err 는 오류 메시지를 출력할 경우 사용된다.

This post is licensed under CC BY 4.0 by the author.