ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 더 빠르게 입력받고 출력해보자 BufferedReader/BufferedWriter
    Knowledge/Java 2019. 9. 4. 22:11
    반응형

    알고리즘 문제를 풀 때 가장 좋은 입출력 방법은? (C, C++, Java ) ( https://takeknowledge.tistory.com/43 )에도 포스팅했지만 java에서 가장 빠르게 입벽받고 출력할 수 있는 방법은 BufferedReader 와 BufferedWriter를 사용하는거다.

     

    입력 속도 비교 ( https://www.acmicpc.net/blog/view/56 ) 에 따르면

    첫째 줄에 정수의 개수 N  (= 10,000,000)

    둘째 줄부터 N개의 줄에 한 개의 자연수(10,000 이하)가 적힌 파일을 입력받는데 

    java에서 무언가를 입력받을 때 주로 쓰는 Scanner는 4.8448초가 걸렸지만

    BufferedReader, Integer.parseInt 를 활용했을 때는 0.6585초가 걸렸을 정도로 차이가 크다.

     

    또한 출력 속도 비교 ( https://www.acmicpc.net/blog/view/57 ) 에 따르면

    총 N개의 줄에 1부터 10,000,000까지의 자연수를 한 줄에 하나씩 출력하는데

    java에서 무언가를 출력할 때 System.out.println(i); 은 무려 30.013초가 걸렸지만

    BufferedWriter, bf.write(i + "\n"); 를 사용했을 때는 0.9581초가 걸렸을 정도로 이 역시 차이가 크다.

     

    결론적으로,  JAVA로 수행 시간이 중요한 알고리즘 문제를 풀때는

    Scanner와 System.out.println을 쓰는 것 보다는 BufferedReader/BufferedWriter를 활용하는 게 훨씬 좋다는 얘기

     

    사용법도 뭐 Scanner와 System.out.println을 쓸때보다는 번거롭지만 그렇게 까지 복잡하진 않다.

    정수 하나를 입력받고 출력하는 예제를 예로 들어보자면

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import java.util.Scanner;
     
    public class inputOutput {
        
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int i = scanner.nextInt();
            
            System.out.println(i);
        }
     
    }
     

     

    이처럼 구현할 수 있지만 이를 BufferedReader/BufferedWriter를 활용하는 방식으로 바꿔보자면

     

    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
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    // BufferedReader 와 BufferedWriter를 사용하기 위해 필요한 것들 
    // 모두 java.io 패키지에 있는 걸 알 수 있다.
    // 따라서 애초에 java.io.* 를 import하고 시작하길 권장한다. 
     
    public class inputOutput {
        
        public static void main(String[] args) throws IOException {
                                             // bufferedReader로 문자열을 입력 받으면 try~catch로 예외 처리를 해줘야 한다.
                                             // 그러나 입력받을 때마다 매번 예외처리하는 건 귀찮은 일..
                                             // 사용하는 메소드에 IOException을 throws해 예외처리를 위임하길 권장한다 
            
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            
            String s = bufferedReader.readLine();
            // readLine 메소드는 String 값만 받을 수 있다.
            int i = Integer.parseInt(s);
            // 따라서 int 형으로 활용하고 싶다면 형변환이 필요하다
            bufferedReader.close();
            // reader를 사용후엔 스트림을 닫아주자!
            
            
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
            bufferedWriter.write(i+"\n");
            // bufferedWriter 는 System.out.println 처럼 자동 개행 처리가 되지 않기 때문에 개행 처리를 따로 해줘야한다.
            // bufferedWriter.newLine(); 을 활용하면 개행처리가 가능하나 이건 "\n"에 비해 속도가 느리다고 하니
            // "\n" 을 활용해 개행처리를 하는 걸 권장한다. 또한 여기엔 하나의 장점이 더 있는데
            // bufferedWriter.write(i); 처럼 writer에 int를 넣으면 아스키 코드에 따른 char형 값이 출력된다.
            // 그러나 i와 개행 처리 문자열 "\n" 을 더하면 String 으로 자동 형변환 되기 때문에 
            // 저장되어 있는 int 값 그대로 출력이 가능하다. 여러모로 이 편이 좋다는 얘기 
            
            bufferedWriter.flush();
            // 다 사용했으면 남아있는 데이터를 모두 출력시키고
            bufferedWriter.close();
            // 스트림을 닫아주면 된다.
            
        }
     
    }

     

    위와 같다. 확실히 코드가 길지만 주석으로 주저리 달아놓은 포인트들을 정리하자면 아래와 같다.

     

    BufferedReader 와 BufferedWriter를 사용하려면

     

    1.  import java.io.*; 선언

     

    2. throws IOException 으로 사용하는 메소드에  예외처리를 위임해라 ( try ~ catch로 해도 되지만.. )

     

    3. readLine() 은 String만 리턴한다. 다른 자료형으로 활용하려면 형변환해라.

     

    4. reader도 writer도 사용후엔 스트림을 닫아주자.

       writer는 닫기전에 flush를 활용해 남아있는 데이터를 모두 출력시켜야한다.

     

    5. 개행처리는 +"\n"을 활용하는 걸 추천한다. newLine() 을 활용할 수도 있지만 개행문자와 비교하면 속도가 느리고

       다른 자료형을 출력할 땐 String으로 형변환도 해주니

       int를 출력했는데 아스키 코드 숫자에 해당하는 문자가 출력되는 일을 막아줄 수도 있다.

    반응형

    댓글

Designed by Tistory.