## 29. 입출력 성능을 높이기 위해 버퍼 기능 추가하기
- 기존의 클래스에 버퍼 기능을 추가한다.
- BufferedDataInputStream = DataInputStream + 버퍼 기능
- BufferedDataOutputStream = DataOutputStream + 버퍼 기능
ㄴ DataInputStream 클래스를 복사하여 BufferedDataInputStream 라는 이름의 클래스를 생성
ㄴ DataOutputStream 클래스를 복사하여 BufferedDataOutputStream 라는 이름의 클래스를 생성
BufferedFileOutputStream.java
package com.eomcs.io.ex06;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferedFileOutputStream extends FileOutputStream {
byte[] buf = new byte[8192];
int cursor;
public BufferedFileOutputStream(String filename) throws Exception {
super(filename);
}
// 오버라이딩: 상속 받은 메서드를 서브 클래스의 역할에 맞춰서 재정의 한다.
// 즉 버퍼를 사용하는 특징에 맞춰서 데이터를 파일에 출력하도록 변경한다.
@Override
public void write(int b) throws IOException {
if (cursor == buf.length) { // 버퍼가 다차면
super.write(buf); // 버퍼에 들어있는 데이터를 한 번에 출력한다.
cursor = 0; // 다시 커서를 초기화시킨다.
}
// 1바이트 출력하라고 하면 일단 버퍼에 저장할 것이다.
buf[cursor++] = (byte) b;
}
// 버퍼를 사용할 때는 특히 주의해야 한다.
// 버퍼가 꽉 찼을 때만 파일로 내보내기 때문에
// 버퍼에 잔여 데이터가 남아 있을 수 있다.
// 버퍼의 잔여 데이터를 강제로 출력하도록 상속 받은 다음 메서드를 재정의 한다.
@Override
public void flush() throws IOException {
if (cursor > 0) {
this.write(buf, 0, cursor);
cursor = 0;
}
}
// 항상 입출력 스트림을 사용한 다음에는 자원 해제를 위해 close()를 호출해야 한다.
// close()가 호출될 때 버퍼의 잔여 데이터를 내보내도록 상속 받은 메서드를 재정의 한다.
@Override
public void close() throws IOException {
this.flush();
super.close();
}
}
BufferedFileInputStream.java
package com.eomcs.io.ex06;
import java.io.FileInputStream;
import java.io.IOException;
public class BufferedFileInputStream extends FileInputStream {
byte[] buf = new byte[8192];
int size; // 배열에 저장되어 있는 바이트의 수
int cursor; // 바이트 읽은 배열의 위치
public BufferedFileInputStream(String filename) throws Exception {
super(filename);
}
// 파일에서 버퍼로 왕창 읽어 온 횟수
int readCount = 0;
// 버퍼를 사용하는 서브 클래스의 특징에 맞춰서
// 상속 받은 메서드를 재정의 한다.
@Override
public int read() throws IOException {
if (size == -1 || cursor == size) { // 바이트 배열에 저장되어 있는 데이터를 모두 읽었다면,
if ((size = super.read(buf)) == -1) { // 다시 파일에서 바이트 배열로 데이터를 왕창 읽어 온다.
return -1;
}
readCount++;
System.out.printf("==>버퍼로 왕창 읽었음! - %d 번째\n", readCount);
cursor = 0;
}
return buf[cursor++] & 0x000000ff;
// 위의 리턴 문장은 컴파일 할 때 아래의 문장으로 바뀐다.
// int temp;
// temp = buf[cursor];
// cursor++;
// return temp & 0x000000ff;
}
}
BufferedDataOutputStream.java
ㄴ BufferedFileOutputStream 클래스를 참고하여 해당 코드를 복사해와서 붙여넣기
BufferedDataOutputStream.java
ㄴ BufferedFileOutputStream 클래스를 참고하여 해당 코드도 복사해오기
BufferedDataOutputStream.java
ㄴ [Command] + space 를 이용하여 write(byte[] b) 메서드 오버라이딩 하기
BufferdDataOutputStream.java
=>
ㄴ flush() 메서드 오버라이딩 하기 -> 출력 스트림에 잔류하는 데이터를 강제로 모두 내보내는 역할
ㄴ cursor 는 0으로 초기화시켜줌
BufferdDataOutputStream.java
ㄴ close() 메서드 오버라이딩
=> flush() 를 close() 할 때 자동 실행되도록 설정해줌
BufferedDataOutputStream.java
ㄴ 주어진 바이트 배열(arr)을 한 번에 출력하는 코드 추가
BufferedDataInputStream.java
ㄴ BufferedFileInputStream 클래스를 참고하여 해당 코드를 복사해와서 붙여넣기
BufferedDataInputStream.java
ㄴ BufferedFileInputStream 클래스를 참고하여 해당 코드를 복사해와서 붙여넣기
BufferedDataInputStream.java
=>
BufferedDataInputStream.java
ㄴ arr 배열의 길이만큼 반복문을 실행
ㄴ this.read() 메서드를 호출하여 하나의 바이트를 읽어오도록 함
ㄴ 만약 읽어온 바이트가 -1이라면(데이터를 더 이상 읽을 수 없을 경우), 현재까지 읽은 데이터의 개수 i를 반환하도록 함
ㄴ 그렇지 않다면, 읽어온 바이트를 arr 배열의 해당 인덱스에 저장하도록 함
ㄴ 반복문이 모두 실행되었다면, arr 배열의 길이를 반환하도록 함
BufferedDataInputStream.java
ㄴ close() 메서드 오버라이딩
App.java
ㄴ 생성한 BufferedDataInputStream 클래스 이용
App.java
ㄴ 생성한 BufferedDataOutputStream 클래스 이용