[java] 데이터 입력(InputStreamReader, BufferdReader)

programmeaow·2022년 5월 27일
0

Java

목록 보기
1/13

java.io package에서 제공하는 다양한 API중 데이터 입출력이 가능한 기능이 있다.
이것을 통해 콘솔 창에 데이터를 입력하고, 입력받은 값이 다시 출력되게 할 수 있다.

java의 데이터 흐름(stream)은 단방향이라 읽기 혹은 쓰기만 가능하다.
즉, 하나의 클래스가 읽고 쓰기 모두는 불가능하다!

- 데이터 입출력 API

1byte 크기의 데이터를 읽는 API들은 ~InputStream
1byte 크기의 데이터를 출력하는 API들은 ~OutputStream

2byte 크기의 데이터를 읽는 API들은 ~Reader
2byte 크기의 데이터를 출력하는 API들은 ~Writer 가 뒤에 붙어서 이름으로 구분이 가능하다.

ex ) 1. 데이터를 file로부터 read 하는 기능
		1byte : FileInputStream   / 2byte :  FileReader
		
 	 2. 데이터를 file로부터 write 하는 기능
		1byte : FileOutputStream   / 2byte :  FileWriter
		
	 3. 1byte와 2byte 모두 호환되는 기능
		read : InputStreamReader / writer : OutputStreamWriter

1byte와 2byte 모두 호환 가능한 API인 InputStreamReader에 대하여 알아보자.

- InputStreamReader

public void test1() {
InputStreamReader read = new InputStreamReader(System.in);
}

생성은 이와 같이 가능하지만 바로 읽는 기능을 사용할 수는 없다.

입력 값이 없는 예외가 생길 수 있기 때문에 exception 처리를 위해 try~catch 문장을 사용하여 읽어들인 값을 출력하는 출력문을 함께 작성했다.

@Test //lombok을 이용하여 @Test로 실행했다.
public void test1() {
InputStreamReader a = new InputStreamReader(System.in);

	try {
		System.out.println(a.read()); 
        
		} catch (IOException e) {
			e.printStackTrace();
		}
}

콘솔 창에 문자를 입력하면 입력한 값이 그대로 출력되게 하는 것이 목표이다.
ex ) a 입력 -> 출력 : a

new InputStreamReader(System.in)에 들어가는 System.in에 대한 설명 정리 글

하지만 위의 코드를 실행하면 a를 입력시 97이 출력되는 것을 볼 수 있는데, 97은 'a'에 해당하는 아스키코드 값이다. [아스키코드 표]

따라서 출력 값이 문자로 나오게끔 출력문에 char로 형변환을 해주어야 한다.

< 수정한 코드 >

@Test 
public void test1() {
InputStreamReader a = new InputStreamReader(System.in);

	try {
		System.out.println((char)a.read()); 
        
		} catch (IOException e) {
			e.printStackTrace();
		}
}

입력 : a
출력 : a

이제 입력한 값과 출력한 값이 동일한 것을 확인할 수 있다.

이번에는 Buffer 기능을 지원하는 BufferedReader를 이용해서 한 글자가 아닌 한 문장 단위로 읽는 readLine( )을 이용해보자.

그런데 버퍼 기능이 대체 무엇을 말하는 걸까?
먼저 버퍼에 대해 알아보자.

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

즉, 버퍼는 임시로 데이터들을 보관하고 있는 영역을 말한다.
readLine을 BufferedReader 없이 작성하게 되면 빨간 밑줄이 생기면서 코드가 실행되지 않는 것을 확인할 수 있다.

자바의 read는 코드를 한 글자씩 읽어서 아스키코드 값으로 저장한다.
따라서 라인 단위로 문자를 읽는다는 것은, 임시 공간에 글자를 한글자씩 읽어서 저장해뒀다가 문장 단위로 한번에 가져오는 것이다.

이제 한 줄 단위로 문자를 읽는 기능을 구현해보자.

@Test 
public void test2() {
	BufferedReader a = new BufferedReader(new InputStreamReader(System.in));
		
		try {
			String data = a.readLine(); //readLine도 발생 가능한 예외때문에 try~catch 사용
			System.out.println(data); 
			
		} catch (IOException e) {
				e.printStackTrace();
		}
}

입력 : abcdefg
출력 : abcdefg

이번에는 한 문장만 읽는 것이 아니라 문장을 계속 입력하면 똑같이 계속 출력되게 하는 기능을 구현해보자.

while(조건문)을 이용해 해당 로직을 작성해보았다.

@Test
public void test2() {
	BufferedReader a = new BufferedReader(new InputStreamReader(System.in));

		try {
			String data = a.readLine();   //0
			while (data != null) { 		  //2
				System.out.println(data); //3
				data = a.readLine();      //1
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

반복문 실행 구조를 보다 쉽게 파악하기 위해 주석을 함께 작성했다.

0에서 문장을 읽고, 2에서 null이 아니면 3으로 넘어가서 문장을 출력한다.
1로 넘어가서 문장을 읽은 뒤 다시 2로 가는데, 여기서 null이 아니면 3으로 넘어가서 다시 문장을 출력하는 것이다.

이렇게 계속 반복하며 문장을 출력하는 구조이다.

. . . . . . .

만약 data에 들어온 값이 null이라면 해당 반복문은 종료될 것이다.
while 반복문이 종료되고 예외는 catch가 잡아서 예외처리가 된다. 하지만 처음 선언한 "BufferedReader a"는 계속 대기 상태로 남아있게 된다.

이 경우 a가 계속 대기 상태로 남아있어 불필요한 자원 소모가 발생한다.
이런 불필요한 자원 소모를 줄이기 위해 java에서는 close( ) 메서드를 제공하고 있다.

- Close( )

.Close( )

Close는 자원을 반환하는 기능을 가지고 있다.
대기 중인 자원이 생길 수 있는 경우에 Close( ) 메서드를 사용하면 '이 자원 이제 그만 쓸게요!' 하고 반납하게 되는 것이다.

try~catch문의 옵션인 finally를 이용하여 Close( )로 자원 반환 로직을 함께 작성해보았다.

finally { 
		try {
			a.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		a = null;
	}

전부 합치면 전체 코드는 이렇게 된다.

public void test2() {
		BufferedReader a = new BufferedReader(new InputStreamReader(System.in));

		try {
			String data = a.readLine();
			while (data != null) {
				System.out.println(data);
				data = a.readLine();
			}

		} catch (IOException e) {
			e.printStackTrace();
		} finally { 
			try {
				a.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			a = null;
		}
	}
profile
개발이란 뭘까

0개의 댓글