Algorithm/Theory

[JAVA] Buffer input/output

youth787 2023. 9. 9. 23:47

Stream

stream : byte 형태로 데이터를 운반하는데 사용되는연결 통로.

물이 한쪽 방향으로만 흐르는 것과 같이 스트림은 단방향 통신만 가능하기 때문에 하나의 스트림으로 입력과 출력을 동시에 처리 할 수 없다. 스트림은 먼저 보낸 데이터를 먼저 받게 되어있으며 연속적으로 데이터를 주고 받는다는 점에서 큐(queue)의 FIFO(First in Frist Out) 구조로 되어 있다.

 

 

Stream 활용 : InputStream / OutputStream

입력 스트림 inputStream 은 스트림을 한 줄 씩 읽고, 출력스트림 outputStream 으로 데이터를 내보내며 해당 공간을 비운다. InputStream 은 System.in을 사용하며, OutputStream 은 System.out 을 사용.

출력을 위해서는 out.write() 후 flush() 와 close() 를 모두 사용해주어야한다.

  • flush 는 write 에 저장된 값을 출력함과 동시에 비워주는 역할.
  • close() 는 끝 마무리해주는 역할.

InputStream / OutputStream는 단 하나의 값밖에 입력받지 못하고, 출력 또한 하나의 값만 입력 받는다.

여러 값을 출력 받기 위한 방법 : InputStreamReader/OutputStreamWriter

다만, InputStreamReader에서 2개 이상의 값을 받아오기 위해서는 배열을 사용해서 값을 받아와야 한다.

⇒ 효율이 나쁘다.

 

 

Buffer

  • Buffer(이하 버퍼)는 위의 InputStream 과 InputStreamReader 를 보완하고 합쳐서 탄생한 입출력의 최종형태.
  • 버퍼는 고정값이 아니라 가변적인 값을 받게 된다.
  • 버퍼는 입력받은 값은 버퍼에 저장해두었다가 버퍼가 가득차거나 개행 문자가 나타나면 버퍼의 내용을 한 번에 전송하게 된다.

 

import java.io.BufferedReader; // 임포트 필수
import java.io.BufferedWriter;

public static void main(String[] args) throws IOException { // 여기도 필수! 아니면 try ~ catch 사용해야함

	InputStream in = System.in;	
	InputStreamReader reader = new InputStreamReader(in);
		
	OutputStream out = System.out;
	OutputStreamWriter writer = new OutputStreamWriter(out);

	// 위의 4줄이 아래의 하나의 줄로 줄어든다
	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 }

 


Buffer 사용법

1) BufferedReader

 

import java.io.BufferedReader; // 임포트 필수
import java.io.BufferedWriter;

public static void main(String[] args) throws IOException {

	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

	String s = br.readLine(); 
    // bufferedReader 의 기본형은 String / 한줄단위로 읽는다. 
		
	int i = Integer.parseInt(s); 
    // String 을 int로 형변환

	br.close(); // bufferedreader 도 입력을 마쳤다면 닫아주자. 필수는 아님.
 }

 

Buffer 의 기본 타입은 String 이며, 엔터(enter)를 경계로 값을 인식한다.

이 때문에 중간에 띄어쓰기(스페이스) 를 기준으로 값을 분리해야하는 경우 따로 데이터를 가공해주어야 한다.

 

2) Stringtokenizer & split

 

StringTokenizer st = new StringTokenizer(br.readLine()); 
	// 한줄씩 읽고 공백단위로 끊어준다.
	// 줄 읽을때마다 새로 변수 생성해야한다. 
	// ex) arr[j] = Integer.parseInt(st.nextToken()); 
    // 공백단위로 끊은 문자열을 정수로 변환해서 각각 배열에 넣어준다. 


	// 위와 같이 공백으로 받을경우 나눠서 담을 수도 있고,
    //.split 사용해서 담는 것도 가능. 하지만 stringtokenizer가 더 효율적.
	String[] s = br.readLine().split(" ");
	// Integer.parseInt(s[0])

 

문자열을 자르게 위해 split을 사용할땐, split은 정규식을 기반으로 자르는 로직으로서 내부는 복잡하다.

그에 비해 StringTokenizer의 nextToken()메소드는 단순히 공백 자리를 땡겨 채우는 것이다. 

그렇기 때문에 소도 차이가 날 수 밖에 없다.

정규식이나 인덱스 접근과 같은 처리가 필요없다면 StringTokenizer를 사용하는 것이 효율적이다. 

 

3) Stringtokenizer 응용

 

BufferedReader br = new BufferedReader(new InputStreamReader(System.in);
StringTokenizer st = new StringTokenizer(br.readLine());

// AB CDD EFFF GH 입력

st.nextToken() // AB
st.nextToken() // CDD
st.nextToken() // EFFF
st.nextToken() // GH


String str = "this%%is%%my%%string"; 
   StringTokenizer st = new StringTokenizer(str,"%%"); 

   while(st.hasMoreTokens()) { 
       System.out.println(st.nextToken()); 
   }
// this is my string

 

4) bufferedwriter

 

bw.write("입력받은 값 : "+ s); // 출력
	bw.newLine(); // 개행 메소드
	bw.write("입력받은 값 : "+i+"\n"); // 이렇게 하니까 제대로 출력됨

	bw.flush(); // 남은 값 출력 && 버퍼 초기화
	bw.close(); // bufferedwriter 닫기

 

bufferedwriter도 기본적으로 string 형태로 출력한다.

따라서 정수형만을 출력하려고 하면 주소값을 출력하게 된다.

br이 integer.parseint 해준 것처럼 bw도 정수값을 출력하려면 변화시켜주어야 한다.

 

for(int i=0; i<onelist.size(); i++) {
			bw.write(String.valueOf(onelist.get(i))); 
            // 정수값 변환하여 출력 
			bw.newLine(); //개행
		}

bw.write(String.valueOf(sum));

br.close();
bw.flush();
bw.close();
반응형