말하는 컴공감자의 텃밭

Java - BufferedReader, StringTokenizer, BufferedWriter 본문

백엔드/Java

Java - BufferedReader, StringTokenizer, BufferedWriter

현콩 2023. 12. 2. 17:03
728x90

BufferedReader, StringTokenizer,  BufferedWriter

코테 준비하면서 자바 기본 I/O인 Scanner 만 사용했었다.

스캐너는 데이터 유형을 유연하게 선택할 수 있지만 속도가 느리다는 단점이 존재했다.

메모리와 속도적으로 알고리즘 문제 풀이에서 제한이 생기는 경우가 존재해서 방식을 바꾸려고한다.

 

백준 입력 속도 비교 https://www.acmicpc.net/blog/view/56

첫째 줄에 정수의 개수 N (= 10,000,000), 둘째 줄부터 N개의 줄에 한 개의 자연수(10,000 이하)가 적힌 파일을 입력받는데 걸리는 시간을 측정. 10번 측정해서 평균값으로 순위를 매김

 

  버퍼 크기 실행 속도(백준 참고)
BufferedReader 8KB 0.6585 sec
Scanner 1KB 4.8448 sec

 

입출력 할 데이터가 많은 경우 위 차이는 더 두드러진다.

 

이러한 큰 차이는 아래 이유이다.

 

Scanner는 데이터 유형에 유연한 편이다.

입력받는 데이터를 token 단위로 잘라 반환하고. 이를 파싱(parse)한다고 할 수 있다.

데이터를 사용자가 필요에 따라서 원하는 타입으로 읽을 수 있다.

데이터 유형에 따른 다양한 함수

 

또한 스캐너는 하나하나 token으로 처리하므로 처리가 오래걸린다.

설거지를 하나 닦고 물로 행구는것보단 모두 닦아두고 한번에 행구는게 빠르듯 버퍼를 활용하는게 효율적이다.

 

BufferedReader은 단순히 String으로만 데이터를 읽어들인다.

readLine()을 활용하고 형변환을 위한 추가적인 코드가 필수적이다. 파싱을 하지 않으며

예외처리가 필수적이다. 버퍼를 활용하기에 월등히 빠른 속도를 자랑한다.

 

물론 입출력이 적은경우 버퍼의 크기가 작은 Scanner가 유리할 수 있다.

 


사용법

 

문제 하나를 입출력 받는 코드를 작성하며 사용법을 익혀보았다.

스캐너처럼 io와 util 라이브러리를 import 해주어야한다. 또한 예외처리를 해주어야한다.

BufferedReader와 BufferedWriter를 사용하여 입출력을 받아준다. 이 둘은 문자 입출력 버퍼 스트림이다.

줄단위로 읽어오기 때문에 StringTokenizer 또는 split()을 통해서 띄어쓰기를 구분해주어야 한다.

 

메서드

readLine() : 데이터를 String 형태로 한줄 읽어 옴.

newLine() : 줄바꿈 메서드

write : 입력 메서드

flush() : 버퍼에 남아 있는 데이터 출력. 버퍼를 비워준다.

close() : 스트림 종료

 


예제 적용 백준 2636번 중

 

입력 형태에 맞춰 사용해 보았다.

import java.util.*;
import java.io.*;


public class Main {// 2636번 치즈 G4
	
	static int N,M,answer,cheese;
	static int [][] arr;
	
	public static  void main(String[] args) throws IOException {
		
	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());
                
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		arr = new int[N][M];
		
		for(int i = 0; i<N; i++) {
			st = new StringTokenizer(br.readLine());
			for(int j = 0; j<M; j++) {
				arr[i][j] = Integer.parseInt(st.nextToken());
			}
		}
	
		bw.write(answer+"\n");
		bw.write(cheese+"\n");
		bw.flush();
		bw.close();
	}
}

 

한줄로 String 으로 받아 N과 M을  StringTokenizer st를 통해 정수형으로 형변환 해준다.

이후 치즈가 있는 부분 역시 st를 활용하여 하나하나 구분해서 배열에 넣어주었다.

 

앞으로 알고리즘을 풀면서 적응을 해봐야겠다.

 

위에 문제 포스팅

https://hb-in99.tistory.com/92

 

백준 2636번 치즈 G4 - BFS

치즈는 위험해..! 문제을 요약하면 1과 0이 맞닿으면 1시간 후, 1이 0이 된다. 모두 사라지는데 걸리는 시간과 사라지기 직전 시간대의 1이 몇개 있는지 출력하면 되는 문제이다. 외각에는 치즈가

hb-in99.tistory.com

 


 

++ 추가내용

 

이제 알았는데 write는 정수형을 출력을 못했다.

버퍼에 숫자 6,2 따로 들어가서 62가 출력될줄 알았는데

 

진짜 우ㅐ저뤱

 

아스키코드로 출력되는것 같았다.

이전 문제 '치즈'에서는 

bw.write(time+"\n");
bw.write(last_cheese+"\n");

 

이런식으로 줄바꿈 문자가 더해져서 문자열로 형변환되어 문제가 없었던 것이었다.

찾아보니BufferedWriter 는 정수형이 char로 변환 되는것을 확인할 수 있었다.

만약 62가 입력으로 들어온다면. (char)62 로 '>' 가 'nextChar' 에 기록되고 ++ 되어 다음 문자를 받을 준비를 한다.

BufferedWriter 의 write메서드

 

버퍼 writer로는 그럼 정수형을 출력할 수 없을까.

결론은 String으로 변환하여 출력하는 방법밖에 없었다. Scanner가 데이터 유형에 강하다는게 체감이 되넹

String.valueOf() 또는 + " " 을 활용해서 형변환 후 출력해주었다.

두가지 예시

 

잘 나온다.

 

짜잘한건데 빠른 시간내에 알게되서 좋았다.

728x90
Comments