알고리즘 공부를 하면 Scanner를 사용하는 일이 많은데,
많은 이들이 BufferedReader 와 BufferedWriter 를 사용하면서 알고리즘 측면에서 더 효율 높다는 것을 발견하였습니다.
초기 System.out.println() 할 데이터의 양이 적다면 큰 차이는 나지 않다고는 하지만, 데이터의 양이 컺리수록 Scanner와 BufferedReader / BufferedWriter의 차이는 더 크다고 합니다.
BufferedReader / BufferedWriter
- Reader, Writer 라는 이름에서 알 수 있겠지만 입출력을 당당하고 있습니다.
- 버퍼를 통해서 입출력을 전달합니다.
그렇다면 위에서 말한 BufferedReader / BufferedWriter이 Scanner 보다 효율이 좋다고 하는데 그 이유는 바로 버퍼를 이용해서 그렇습니다.
-
버퍼는 우리가 키보드에 입력할때마다 값을 전달하는 것이 아니라 버퍼에 정해진 용량만큼 모아놓은 후에 전달을 해줍니다.
-
그림만 보면 이해가 안되겠지만 쉽게 생각해보면
택배 배송을 하는데 하나씩 옮기는 것보다 한꺼번에 옮기는 것이 더 효율적이다! 라고 이해하면됩니다.
-
출력도 마찬가지로 버퍼를 통해서 프로그램에 전달이 되기 때문에 시스템의 데이터처리 효율성을 높여줄 수 밖에 없습니다.
- 버퍼를 사용할 때, inputStream과 OutputStream 을 사용하는 이유가 입출력스트림 으로부터 미리 버퍼에 데이터를 담아주기 때문에 Scanner보다 효율적인 출력이 가능한 것입니다.
Buffer(버퍼) 란 ?
- 데이터를 한곳에서 다른 한곳으로 전송하는 동안 일시적으로 그 데이터를 보관하는 임시 메모리 영역
- 입출력 속도 향상을 위해 버퍼를 사용
- 버퍼 플러시(buffer flush) : 버퍼에 남아있는데이터를 출력시킵니다(버퍼를 비우는 행위)
- BufferedReader : 버퍼를 이용한 입력
- BufferedWriter : 버퍼를 이용한 출력
BufferedReader
- Scanner 로 입력을 할 경우에는 SpaceEnter를 경계로 인식하여 입력한 데이터를 가공하기가 매우 쉽습니다.
- 하지만 BuffredReader 는 Enter로만 인식하고 return 된는 데이터가 String으로 고정되기 때문에 이를 int로 사용하기위해서는 약간의 변형을 줘야합니다.
- 해당 코드가 BufferedReader 의 가장 기본적인 예제라고 볼 수 있습니다.
- 입력하는 값이기 때문에 BufferedReader를 설정해주는데 여기에 InputStreamReader로 같이해줍니다.
- 코드를 보면 readLine()이 있는데 이는 Scanner의 NextLine()의 역할을 하는것이라고 볼 수 있습니다.
- 또한 BuffredReader는 return값이 String으로 고정되기 때문에 int 타입으로 변형시켜 주려면 Integer.parseInt()를 해줘야합니다.
해당 코드는 값 1개를 입력 할 수 있는데, 만약 여러개의 코드를 입력해야 한다면 어떻게 해야할까?
이럴때는 StringTokenizer 클래스를 이용하여 split을 통해 공백을 나눠줘서 작업을 해야합니다.
- readLine() 메서드가 있기 때문에 Scanner 처럼 1과 2를 따로 입력하는것이 아니라 1 2 처럼 한줄에 입력을 해줘야 합니다.
- 1 2 로 입력을 했다면 " "로 된 공백을 포함하여 버퍼에 넣어주게 되고, 이 공백을 나누기 위해서는 StringTokenizer와 Split을 통해 입력한 값을 나눠줍니다.
- 이와 같이 delim(delimit)을 사용하여 나타낼 수도 있습니다.
BuffredWriter
- 흔히 알고 있는 System.out.println() 과 동일 기능을 하는 메서드입니다.
- 이것 또한 버퍼를 이용하기 때문에 효율이 좋고 많은 양의 데이터를 처리할 때 유용합니다.
- BufferdReader와 BuffredWriter를 사용한 예제입니다.
- 해당 메서드를 사용할 때는 bw.write() 처럼 이것을 사용한다고해서 바로 출력되는 것이 아닙니다.
- Scanner 처럼 바로 적용되는 것이아니라 버퍼에 데이터를 저장했다가 버퍼가 flush 나 close가 될때 한번에 Stream 쪽으로 전달이 되기 때문입니다.
- 따라서 해당값을 출력하기 위해서는 bw.flush() 와 bw.close()를 꼭 사용해주어야합니다.
- 만약 계쏙 사용해주고 싶다면 bw.close() 는 완전히 기능을 닫아버리기 때문에 계속하기 위해서는 bw.flush()를 사용해주어야합니다.
- 만약 줄바꿈이 필요하다면 newLine()을 이용해줍니다.
- 또한 write() 메서드는 String으로만 출력이 가능해서 정수값으로 출력하려면 String.valueOf()를 통해 타입을 변환해주어야 합니다.
- 이 메서드는 버펄르 잡아두기 때문에 flush()와 close()를 통하여 처리해 주어야하며, System.out.println() 처럼 자동적으로 개행처리가 안되기 때문에 newLine()이나 \n을 통해 개행처리를 해주는 것이 좋습니다.
메서드 종류와 기능
- BufferedReader(Reader rd) : rd에 연결되는 문자입력 버퍼스트림 생성
- BufferedWriter(Writer wt) : wt에 연결되는 문자 출력 버퍼스트림 생성
- int read() : 스트림으로부터 한 문자를 읽어서 int형으로 리턴
- int read(char[] buf) : 문자배열 buf의 크기만큼 문자를 읽어들입니다.(읽어들인 문자수를 return)
- int read(char[] buf, int offset, int length) : buf의 offset 위치에서부터 length길이만큼 문자를 스트림으로부터 읽어들임
- String readLine() : 스트림으로부터 한 줄을 읽어 문자열로 return 해줍니다.
- void mark() : 현재위치를 마킹, 차후 reset() 을 이용하여 마킹위치로부터 시작
- void reset() : 마킹이 있으면 그 위치에서부터 다시 시작, 그렇지 않다면 처음부터 다시시작
- long skip(int n) : n개의 문자를 건너띔
- void close() : 스트림을 닫음
- void write(int c) : int형으로 문자 데이터를 출력문자스트림으로 출력
- void write(char[] buf, int offset, int length) : 문자열 buf의 offset위치부터 length 길이만큼을 출력스트림으로 출력
- void newLine() : 줄바꿈 문자열 출력
- void flush() : 남아있는 데이터를 모두 출력