Java

[Java] BufferedReader / BufferedWriter 사용법

메바동 2020. 6. 1. 11:20
728x90

코딩 테스트 문제를 풀어보기 위해 Beakjoon Online Judge에서 기초부터 문제를 풀고 있는데 15552번 "빠른 A+B" 문제에서 BufferedReader, Writer에 대해 알게 되었다. 아마 대학에서 배웠을 테지만 쓰지 않다 보니 잊은 것 같다.

1. Buffer

BufferedReader와 BufferedWriter는 버퍼를 이용해서 읽고 쓰는 클래스로, 버퍼를 사용하기 이용하기 때문에 이 함수를 이용하면 입출력의 효율이 좋아진다.

 

이미지

 

키보드나 모니터와 같은 외부 장치와의 데이터 입출력은 CPU의 성능 차이가 크기 때문에 버퍼를 두고 모아두었다 한 번에 전송하는 것이 효율적이다.

2. BufferedReader

BufferedReader는 개행 문자를 경계로 인식하고 받은 데이터가 String으로 고정되기 때문에 데이터를 따로 가공해야 하는 번거로움이 있지만 Scanner에 비해 빠르다는 장점이 있다.

10,000,000개의 0~1023 범위의 정수를 한 줄씩 읽고 입력으로 받은 정수의 합을 출력하는 프로그램을 구현할 때 BufferedReader와 Scanner의 차이는 밑의 표와 같다. [1]

입력방식 수행 시간(초)
java.util.Scanner 6.068
java.io.BufferedReader 0.934

BufferedReader 사용법

BufferedReader의 readLine()을 사용하면 데이터를 한 줄씩 읽을 수 있다. readLine()의 반환 값은 String이기 때문에 다른 타입으로 사용하려면 형 변환을 필수로 해주어야 한다.


import java.io.*;

class BufferedReaderEx {
    public static void main(String[] args) {
        try { // BufferedReader를 사용할 경우 예외처리 혹은 throws IOException을 해주어야 한다.
            // 콘솔에서 입력을 받는 경우
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

            // 파일에서 입력을 받는 경우
            FileReader fr = new FileReader("파일명");
            BufferedReader br_f = new BufferedReader(fr);

            int num = Integer.parseInt(br.readLine());
            br.close(); // 입출력이 모두 끝나면 닫아주어야 한다.

            String line = "";
            for (int i = 1; (line = br_f.readLine()) != null; i++) {
                System.out.println(line);
            }
        } catch(IOException e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }
}

한 줄씩 읽어오는 것이 아닌 공백 단위로 끊어줄 때는 StringTokenizer의 nextToken()을 이요하거나 String의 split()을 이용하면 된다.

BufferedReader의 메소드들

Modifier and Type Method and Description
void close()
입력 스트림을 닫고 사용하던 자원들을 해제한다.
void mark(int, readAheadLimit)
스트림의 현재 위치를 마킹한다.
boolean markSupported()
스트림이 mark 기능을 지원하는지 boolean으로 알려준다.
int read()
한 글자만 읽어 아스키코드 값으로 반환한다.
int read(char[] cbuf, int offset, int length)
cbuf의 offset위치부터 length의 길이만큼 문자를 스트림으로부터 읽어온다.
String readLine()
한 줄을 읽어온다.
boolean ready()
입력 스트림이 사용할 준비가 되어있는지 알려준다.
void reset()
읽는 위치를 처음으로 변경한다. 마킹이 되어있을 경우 마킹된 위치로 변경된다.
long skip(long n)
n개의 문자를 건너뛴다.

3. BufferedWriter

System.out.print()와 동일한 기능을 하는 클래스로 버퍼를 이용하기 때문에 속도가 빠르다. System.out.println()처럼 개행을 동시에 해주지 않기 때문에 개행을 하면 write에 "\n"을 넣어주거나 newLine()을 사용해야 한다.

BufferedWriter 사용법


import java.io.*

class BufferedWriterEx {
    public static void main(String[] args) {
        BufferedWriter bw = new BufferedWriter(new FileWriter("파일명"));
        bw.write("출력할 내용 \n");
        bw.newLine();   // 개행
        bw.flush(); // 남은 데이터 모두 출력
        bw.close(); // 스트림 닫기
    }
}

BufferedWriter를 사용 후 닫기 전에 flush()를 이용하여 버퍼를 비워주어야 한다.

BufferedWriter의 메소드들

Modifier and Type Method and Description
void close()
스트림을 닫는다.
void flush()
스트림을 비운다.
void newLine()
개행 문자를 출력한다.
void write(char[] cbuf, int offset, int length)
버퍼 offset위치부터 length크기만큼 출력한다.
void write(int c)
한 글자를 출력한다.
void write(String s, int offset, int length)
문자열에서 offset부터 length만큼 출력한다.

※ String, StringBuffer, StringBuilder

  • String : String은 리터럴을 통해 생성되면 그 인스턴스의 메모리 공간은 절대 변하지 않는다. '+' 연산이나 concat()을 이용해 문자열 값에 변화를 줘도 메모리 공간 내의 값이 변하는 것이 아니라 "String Pool"이라는 공간 안에 메모리를 할당 받아 새로운 String 클래스 객체를 만들어 문자열을 나타내는 것이다.

    • String 클래스는 문자열 연산이 적고, 자주 참조(조회)하는 경우에 사용하면 좋다. (특히 멀티 스레드 환경에서 신경 쓸 것이 없어서 좋다.)
  • StringBuffer, StringBuilder : String과 다르게 변경이 가능하므로 한 번만 만들고 메모리의 값을 변경시켜서 문자열을 변경한다. StringBuffer와 StringBuilder의 차이는 StringBuffer는 멀티 스레드 환경에서 synchronized 키워드를 이용해 동기화가 가능하다. 즉, thread-safe히다. 반대로 StringBuilder는 thread-safe하지 않다. 대신 싱글 스레드 환경에서는 StringBuilder가 연산처리가 빠른 장점이 있다.

    • StringBuffer와 StringBuilder는 문자열 연산이 많을 때 사용하면 좋고 멀티 스레드 환경에서는 StringBuffer, 싱글 스레드 환경이거나 동기화가 필요 없는 경우에는 StringBuilder를 사용하면 좋다.

Reference

728x90