BufferedReader, BufferedWirter 사용법

ChoRong0824·2023년 2월 14일
1

Java

목록 보기
5/31

Scanner

BufferedReader 를 보기 전에 먼저 Scanner을 확인.
대부분 Java를 처음 배울 때, Scanner를 통한 입출력을 먼저 배우게 됩니다.
필자 또한 그랬습니다.
Scanner은 띄어쓰기와 개행문자를 경계로 하여 입력 값을 인식합니다. 그렇기 떄문에 따로 가공할 필요가 없어서 편리합니다.

가공할 필요가 없다는 뜻은 int형 변수를 입력 받고자 하면, int x = scanner.nextInt() 를 사용해 바로 원하는 타입의 입력을 받을 수 있습니다.
하지만, 이번에 살펴볼 BufferedReader은 입력 받은 데이터가 String 으로 고정되기 때문에 입력받은 데이터를 원하는 타입으로 가공하는 작업이 필요합니다.

scanner는 지원해주는 메소드가 많고, 사용하기 쉬우나, 많은 입력을 필요로 할 경우에는 버퍼 사이즈가 작아 효율적이지 못하고 성능상 좋지 못한 결과를 불러옵니다.


간단하게

BufferedReader은 Scanner 즉. 입력 값을 받는다고 보면 된다.
BufferedWriter은 sout 즉, 출력하는 문구라고 생각하면 된다.


자세하게

BufferedReader 와 BufferedWriter는 버퍼를 사용하여 읽기와 쓰기를 하는 함수입니다.

버퍼를 사용하지 않는 입력 : 키보드의 입력이 키를 누르는 즉시 바로 프로그램에 전달됩니다.

반면, 버퍼를 사용하는 입력 : 키보드의 입력이 있을 때마다 한 문자씩 버퍼로 전송합니다. __버퍼가 가득 차거나 혹은 개행 문자가 나타나면 버퍼의 내용을 한 번에 프로그램에 전달합니다.

한번 버퍼를 거쳐 출력되는 것보다, 키보드의 입력을 받는 즉시 출력하는 것이 더 빠른 것이 아닌가 라는 생각을 할 수 있습니다.

그러나, 하드디스크는 속도가 느립니다. 그리고 외부장치 (키보드,모니터 등)와 데이터 입출력도 생각보다 시간이 오래 걸립니다.

그렇기 때문에 키보드의 입력이 있을 때마다 바로 이동시키는 것 보다는, 입력 중간에 버퍼를 두어 한번에 묶어 보내는 것이 더 효율적이고 빠른 방법입니다.
예) 쓰레기통을 비우는 일이라고 생각하면 이해하기 쉽습니다.
쓰레기가 생길 때마다 하나씩 밖에 내다 버리는 것 보단, 쓰레기통이 꽉 차면 밖에 버리는 것이 훨씬 더 효율적인 것과 비슷한 개념이라고 생각하면 됩니다.


쓰는 이유

버퍼를 이용하면 속도가 훨씬 빠르기 때문에 사용한다.
입력된 데이터가 바로 전달되지 않고, 버퍼를 거쳐 전달되므로 데이터 처리 효율성을 최대한으로 높입니다. => 많은 양의 데이털르 처리할 때 유리합니다.
하지만 BufferdReader은 Enter만 경계로 인식하며, 받은 데이터는 String 으로 고정되기 때문에 입력 받은 데이터를 가공하는 작업이 필요한 경우가 많습니다.

그리고 입력이 많을 때 BufferedReader가 유리하다 (버퍼 사이즈가 압도적으로 큼).
또한 BufferedReader는 동기화 되기 때문에 멀티 쓰레드 환경에서 안전하고, Scanner는 동기화가 되지 않기 때문에 멀티 쓰레드 환경에서 안전하지 않습니다.


사용법

BufferedReader bf = new BufferedReader(new InputStreamReader(System,in)); //선언
String s = bf.readLine(); //String 초기화
int i = Integer.parseInt(bf.readLine()); //Int 초기화

readLine() 이라는 메서드를 활용해서 입력합니다.

readLine() 사용시 주의점

readLine() 시 리턴 값을 String 으로 고정되기에 String이 아닌 다른 탕비으로 입력을 받으려면 형 변환은 꼭 해주어야합니다.
또한, 예외처리를 꼭 해줘야합니다.
readLine()을 할 때마다 try&catch를 활용하여 예외처리를 해주어도 되지만 대개 throws IOException을 통하여 작업합니다.

throw 이용시

  1. 클래스를 import 해줍니다.
    import java.io.IOException;

  2. main 클래스 옆에 throws IOException를 작성합니다.
    public static void main(String[]args)throws IOException{}


공백단위로 데이터 가공시 필요한 작업

BufferedReader를 통해 읽어온 데이터는 개행문자 단위(Line 단위)로 나누어진다. 만약 이를 공백 단위로 데이터를 가공하고자 하면 따로 작업을 해주어야 한다. 이때 사용하는 것이 StringTokenizer나 String.split() 함수이다.

StringTokenizer st = new StringTokenizer(s); // StringTokenizer 인자값에 입력 문자열 넣음
int a = Integer.parseInt(st.nextToken()); // 첫 번째 호출
int b = Integer.parseInt(st.nextToken()); // 두 번째 호출

String arr[] = s.split(" "); // 공백마다 데이터 끊어서 배열에 넣음

Read한 데이터는 Line단위로만 나눠지기 때문에, 공백 단위로 데이터를 가공하려면 따로 작업해줘야 합니다.

대표적으로 두가지 방법이 있는데,

  1. StringTokenizer에 nextToken()함수를 사용하면 readLine()을 통해 입력받은 값을 공백 단위로 구분하여 순서대로 호출할 수 있습니다.
  2. String.split()함수를 활용하여 배열에 공백단위로 끊어서 데이터를 넣고 사용할 수 있습니다.

BufferedReader 클래스의 메인 함수들


BufferedWriter

BufferedWriter bw = new BufferedWriter(newOutputStreamWriter(Sytem.out));

할당된 버퍼에 값 넣어주기

String s = "abcd"; //출력할 문자열
bw.write(s+"\n"); //버퍼에 있는 값 전부 출력
bw.flush(); // 남아있는 데이터를 모두 출력
bw.close(); // 스트림 닫기

(Scanner이랑 사용법이 유사하다고 생각하면 편함)
BufferedWriter 의 경우 버퍼를 잡아 놓았기 때문에 반드시. flush() / close() 를 반드시 호출해 주어 뒤처리를 해주어야 합니다.
그리고 bw.write에는 System.out.println();과 같이 자동개행 기능이 없기 때문에 개행을 해주어야할 경우에는 \n를 통해 따로 처리해주어야합니다.

BufferedWriter 클래스의 메인 함수들


StringBuilder

알고리즘 연습 문제를 풀다보면, BufferdReader/BufferedWriter만큼 StringBuilder도 많이 사용하는 것을 볼 수 있다.

  • String과 StringBuffer와의 차이점
    이들의 가장 큰 차이점은, String은 불변 속성을 갖고, StringBuffer/StringBuilder는 그렇지 않다는 것이다.

String이 불변성을 갖는 다는 의미는, concat이나 + 연산을 통해 값을 변경하면, 원래 기존의 String 메모리에서 값이 바뀌는 것이 아니라, 기존의 String에 들어있던 값을 버리고 새로운 값을 재할당하게 된다. 처음에 할당한 String의 메모리 영역은 Garbage로 남아있다가 GarbageCollection)에 의해 없어진다.

String은 불변성을 가지기 때문에 변하지 않는 문자열을 자주 읽어들이는 경우 사용하면 유리하다. 하지만 문자열 추가, 삭제, 수정 등의 연산이 자주 일어나는 경우에 String을 사용하면, 힙 메모리에 많은 Garbage가 생성되고, 이는 힙 메모리 부족으로 이어져 프로그램의 성능에 치명적 영향을 미칠 수 있다.

이를 해결하기 위해 나온 것이 StringBuffer/StringBuilder이다.

StringBuffer/StringBuilder는 가변성을 가지기 때문에, .append() , .delete()등 동일 객체 내에서 문자열을 변경하는 것이 가능하다. 그렇기 때문에 문자열의 추가, 수정, 삭제가 빈번하게 발생할 경우 사용해야 한다.

  • StringBuffer vs StringBuilder

StringBuffer : 동기화를 지원하여 멀티 쓰레드 환경에서 안전하다.

StringBuilder : 동기화를 지원하지 않아 멀티 쓰레드 환경에 사용하기 적합하지 않다. 대신, 동기화를 지원하지 않기에 단일쓰레드에서는

                    StringBuffer보다 성능이 뛰어나다.

정리하자면, StringBuilder는 문자열의 연산이 자주 일어나는 단일 쓰레드 환경에서 사용하는 것이 유리하다.

사용법

StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append("b").append(" ");
sb.append("c").append("\n");

StringBuilder 주요 메소드

  • StringBuilder append(String s) : StringBuilder 뒤에 값을 붙임
  • StringBuilder delete(int start , int end) : 특정 인덱스부터 인덱스까지를 삭제
  • StringBuilder insert(int offet, any primitive of a char[]) : 문자를 삽입함
  • StringBuilder replace(int start , int end , String s) : 일부를 String 객체로 치환
  • StringBuilder reverse() : 순서를 뒤집음
  • StringBuilder setCharAt(int index , char ch) : 주어진 문자를 치환
  • StringBuilder indexOf(String s) : 값이 어느 인덱스에 들어있는지 확인
  • StringBuilder subString(int start, int end) : start와 end 사이의 값을 잘라옴.
profile
컴퓨터공학과에 재학중이며, 백엔드를 지향하고 있습니다. 많이 부족하지만 열심히 노력해서 실력을 갈고 닦겠습니다. 부족하고 틀린 부분이 있을 수도 있지만 이쁘게 봐주시면 감사하겠습니다. 틀린 부분은 댓글 남겨주시면 제가 따로 학습 및 자료를 찾아봐서 제 것으로 만들도록 하겠습니다. 귀중한 시간 방문해주셔서 감사합니다.

0개의 댓글