반응형

BufferedReader / BufferedWriter

bufferedReader, bufferedWriter는 이름에서 확인할 수 있듯이 버퍼를 이용하여 읽고 쓰는 역할을 하는 메서드입니다.

버퍼란?

  • 버퍼는 데이터를 한 곳에서 다른 한 곳으로 전송하는 동안 일시적으로 그 데이터를 보관하는 메모리 영역.

자바의 Scanner와 BufferedReader의 차이점

  • Scanner는 띄어쓰기(스페이스)와 줄바꿈(엔터, 개행문자)를 경계로 값을 인식
  • BufferedReader는 줄바꿈(엔터, 개행문자)만 경계로 인식 + 데이터의 타입이 무조건 String으로 고정.

버퍼를 사용하지 않는 입력(Scanner)는 키보드의 입력이 키를 누르는 즉시 바로 프로그램에게 전달이 되지만, 
버퍼를 사용하는 입력(BufferedReader)는 키보드의 입력이 있을 때마다 한 문자씩 버퍼로 전송한 후, 버퍼가 가득 차거나 줄 바꿈(\n)이 나타나면 버퍼에 쌓인 내용을 한 번에 프로그램에 전송해줍니다.

 

이렇게 버퍼를 사용하지 않는 입력은 키보드의 입력이 되는 즉시 프로그램에 보내지고, 버퍼를 사용하는 입력은 버퍼에 저장되었다가 한 번에 보내면 더 비효율인 것처럼 생각될 수 있다. 하지만 데이터의 입출력은 자원이 많이드는 작업이기 때문에 하나씩 바로바로 보내주는 것보다 모아서 한번에 보내주는 것이 더 효율적입니다.

 

예를들면, 무거운 상자들을 먼 거리로 옮겨야하는 상황일 때 버퍼는 사용하지 않는 입력은 상자를 하나씩 옮기는 것이고 버퍼를 사용하는 입력은 엘카(물건들을 적재한 후 한 번에 옮기게 해주는 도구)에 물건들을 쌓고 한 번에 옮기는 것입니다.

 

이러한 특징으로 빠른 입/출력이 가능한 BufferedReader, BufferedWriter는 자바 / 코틀린으로 입출력을 다뤄야하는 알고리즘 문제를 풀때 입출력 시간을 단축시키기위하여 사용하는 모습을 자주 볼 수 있습니다.


BufferedReader 사용하기

import java.io.BufferedReader
import java.io.File
import java.io.FileReader

fun main() {

    // 예외 처리하기
    try {
        // 콘솔로 입력을 받을 때
//    val br = BufferedReader(InputStreamReader(System.`in`))

        // 파일 경로 설정
        val path = System.getProperty("user.dir") + "/src/main/kotlin"
        // 파일 객체 생성
        val file = File(path, "test.txt")
        // 파일에서 입력을 받을 때(파일 읽기)
        val br = BufferedReader(FileReader(file))

        // 파일의 끝까지 한 줄씩 반복해서 출력(String)
        while (true) {
            // 무조건 string으로 반환, 다른 데이터 타입은 형변환이 필요함.
            val line = br.readLine() ?: break
            println(line)
        }

        br.close()
    } catch (e: Exception) {
        println("$e 에러 발생")
    }

}

이 코드는 현재 디렉터리 + /src/main/kotlin에 있는 test.txt라는 이름을 가진 파일을 읽어온 후 한 줄씩 출력해주는 코드입니다.
try catch 구문을 사용하여 예외처리를 해주었습니다.

콘솔로 직접 입력을 받을 때에는 맨 위에 주석처리된 val br = BufferedReader(InputStreamReader(System.`in`)) 와 같이 사용하면 됩니다.

// 파일의 끝까지 한 줄씩 반복해서 출력(String)
while (true){
    // 무조건 string으로 반환, 다른 데이터 타입은 형변환이 필요함.
    val line = br.readLine() ?: break
    println(line)
}

br.readLine()을 통해 해당 파일의 내용을 한줄씩 반복해서 읽고, 출력하는 부분입니다. BufferedReader는 '\n' 즉, 줄바꿈을 기준으로 문자열을 나누기 때문에 만약 공백, 혹은 특정 문자를 기준으로 문자열을 더 나누고 싶다면 split함수 혹은 StringTokenizer를 사용하여 문자열을 더 나눠줄 수 있습니다.

 


BufferedReader 클래스의 또 다른 메인 함수들

  • close() - void 반환
    • 입력스트림을 종료하고 사용하던 자원들을 방출하는 메서드
  • mark(int readAheadLimit) - void 반환
    • 스트림의 현재 위치를 마킹하는 메서드
  • markSupported() - boolean 반환
    • 스트림이 mark 기능을 지원하는지 true/false 여부로 알려주는 메서드
  • read() - int 반환
    • 한 글자만 읽은 후 아스키 코드를 정수형으로 반환해주는 메서드
    • ex) 1을 읽었다면 49라는 정수를 반환
  • read(char[] cbuf, int offset, int length) - int 반환
    • cbug의 offset 위치부터 length 길이만큼 문자를 스트림으로부터 읽어오는 메서드
  • readLine() - String 반환
    • 한 줄을 읽은 후 해당 문자열을 String으로 반환하는 메서드
  • ready() - boolean 반환
    • 입력스트림이 사용할 준비가 되어있는지 확인해주는 메서드
  • reset() - void 반환
    • 마킹이 있다면 그 위치부터 다시 시작, 그렇지 않으면 처음부터 다시 시작하는 메서드
  • skip(long n) - long 반환
    • n개의 문자를 건너뛰는 메서드

BufferedWriter 사용하기

import java.io.*

fun main() {

    // 콘솔에서 BufferedReader로 입력 받기
    val br = BufferedReader(InputStreamReader(System.`in`))
    // 입력받은 데이터에서 한줄만 input에 String으로 저장
    val input = br.readLine()

    // BufferedWriter 객체 생성
    val bw = BufferedWriter(OutputStreamWriter(System.out))

    // input을 저장 쓰기
    bw.write(input)
    // 개행문자 쓰기
    bw.newLine()
    // 문자열이라는 문자열을 쓰기
    bw.write("문자열")
    // 버퍼에 남아있는 데이터들을 출력 후 비우기 - 콭솔에 출력
    bw.flush()
    // 스트림 종료
    bw.close()

    // 여기부터는 파일 쓰기
    // 파일을 생성할 경로 지정
    val path = System.getProperty("user.dir") + "/src/main/kotlin"
    // 파일의 경로, 생성할 파일의 이름을 가지는 File 객체 생성
    val file = File(path, "test.txt")
    // FileWriter 객체 생성
    val fileWriter = FileWriter(file)
    // 생성할 파일, 경로의 정보가 담긴 FileWriter를 가지는 파일 생성용 BufferedWriter 객체 생성
    val bwForFile = BufferedWriter(fileWriter)

    // input을 쓰기
    bwForFile.write(input)
    // 개행문자 쓰기
    bwForFile.newLine()
    // 문자열이라는 문자열을 쓰기
    bwForFile.write("문자열")
    // 버퍼에 남은 값 출력 및 비우기
    bwForFile.flush()
    // 스트림 종료
    bwForFile.close()


}

이 코드는 두 가지의 BufferedWriter의 기능이 담겨있습니다.
첫 번째는 콘솔에서 BufferedReader로 입력받아 BufferedWriter로 콘솔창에 출력하는 것이고
두 번째는 BufferedWriter로 파일쓰기를 하는 것입니다.

// input을 쓰기
bw.write(input)
// 개행문자 쓰기
bw.newLine()
// 문자열이라는 문자열을 쓰기
bw.write("문자열")
// 버퍼에 남아있는 데이터들을 출력 후 비우기 - 콭솔에 출력
bw.flush()
// 스트림 종료
bw.close()

write()는 인자로 들어온 문자열을 버퍼에 저장하는 메서드이고

newLine()은 개행 문자를 버퍼에 저장하는 메서드 입니다.

flush()는 버퍼에 남아있는 데이터들을 출력하고 비워줍니다.

// 여기부터는 파일 쓰기
// 파일을 생성할 경로 지정
val path = System.getProperty("user.dir") + "/src/main/kotlin"
// 파일의 경로, 생성할 파일의 이름을 가지는 File 객체 생성
val file = File(path, "test.txt")
// FileWriter 객체 생성
val fileWriter = FileWriter(file)
// 생성할 파일, 경로의 정보가 담긴 FileWriter를 가지는 파일 생성용 BufferedWriter 객체 생성
val bwForFile = BufferedWriter(fileWriter)

// input을 쓰기
bwForFile.write(input)
// 개행문자 쓰기
bwForFile.newLine()
// 문자열이라는 문자열을 쓰기
bwForFile.write("문자열")
// 버퍼에 남은 값 출력 및 비우기
bwForFile.flush()
// 스트림 종료
bwForFile.close()

쓰기를 진행할 파일명, 경로의 정보를 가지는 FileWriter 객체를 BufferedWriter에게 넘겨주어 해당 경로에 해당 파일명을 가지는 파일을 쓰도록 지정해줍니다.


BufferedWriter 클래스의 또 다른 메인 함수들

  • flush()
    • 스트림을 비워주는 메서드
  • close()
    • 스트림을 닫는 메서드. flush()를 먼저 해야함.
  • newLine()
    • 개행문자를 쓰는 메서드
  • write(char[] cbuf, int offset, int length)
    • 버퍼 offset 위치부터 length 크기만큼 쓰는 메서드
  • write(int c)
    • 한 글자를 쓰는 메서드
  • write(String s, int offset, int length)
    • 문자열에서 offset부터 일정 길이만큼 쓰는 메서드

참고

https://doozi316.github.io/java/2021/03/22/JAVA1/

https://jhnyang.tistory.com/92

반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기