포스트

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 클래스를 사용하여 문자열을 읽고 쓰는 기능을 제공