[Java] BufferedInputStream / BufferedOutputStream
ํ๊ทธ: Java, Refactoring
์นดํ ๊ณ ๋ฆฌ: Java
- ์ด์ ๊ธ์ ์ด์ด์ ํ์ผ ์ ์ถ๋ ฅ ์ฑ๋ฅ์ ๊ฐ์ ํด๋ณธ๋ค.
- ๋ฒํผ(buffer)๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ์ด์ ๋ฅผ ์์๋ณธ๋ค.
FileInputStream / FileOutputStream ์ ๊ทธ๋๋ก ์ฌ์ฉ ์ ๋ฌธ์ ์
Hdd
ํ์ผ์ ์ฝ๊ณ ์ฐ๋ ์์
์ ํ๋ write()
์ read()
๋ JNI(Java Native Interface)๋ฅผ ํตํด ์ง์ OS์ API๋ฅผ ํธ์ถํด ํ๋์จ์ด๋ฅผ ์ ์ดํ๋ค๊ณ ํ๋ค.
์ฝ๊ณ ์ฐ๋ ์์
์ด ์ฆ๊ฐํ๋ฉด ์ด API ํธ์ถ ํ์ ๋ํ ์ฆ๊ฐํ๊ฒ ๋๊ณ , ์ด๋ ํ๋์จ์ด(HDD)์ ์ ๊ทผํ๋ ํ์ ๋ํ ์ฆ๊ฐํ๋ค๋ ๊ฒ์ด๋ค.
๋ฌธ์ ๋ HDD์ ๋์๋ฐฉ์์ ์๋ค. ์ ํต์ ์ธ ํ๋ ๋์คํฌ๋ ๋ฐ์ดํฐ๋ฅผ ๋์คํฌ์ ์ฝ๊ณ ์ธ๋ ๋ฌผ๋ฆฌ์ ์ผ๋ก ์์ง์ด๋ ์๊ฐ์ด ํ์ํ๋ฐ ๋ค์์ ์ธ๊ฐ์ง ์์๋ค์ ์ด ํฉ์ผ๋ก ๊ฒฐ์ ๋๋ค.
- seek time : hdd์ arm์ด ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์ฐ๊ธฐ ์ํด ์ ์ ํ ์์น๊น์ง ์ด๋ํ๋๋ฐ ๊ฑธ๋ฆฌ๋ ์๊ฐ
- rotational time : arm์ head ์๋๋ก ๋์คํฌ๋ฅผ ํ์ ์์ผ ์ด๋์ํค๋๋ฐ ๊ฑธ๋ฆฌ๋ ์๊ฐ
- transfer time : ๋์คํฌ์ ๋ฐ์ดํฐ์ ์ด ๊ธธ์ด๋งํผ ์ฝ๊ณ ์ฐ๋ ์๊ฐ
write()
, read()
๋ฅผ ๊ณ์ํด์ ํธ์ถํ๊ฒ ๋๋ฉด ์์ ๊ณผ์ ์ด ๋ฐ๋ณต์ ์ผ๋ก ์ผ์ด๋๋ค.
๋ง์ฝ ์ดํ๋ฆฌ์ผ์ด์
์์ ์ด๋ฐ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ์ ์
์ถ๋ ฅ์ ๋ค๋ฃฌ๋ค๋ฉด I/O-burst ์ํฉ์ด ์๊ธฐ๋ฉฐ, I/O ์์
์ ํ๋ ๋์ ์๋น์ค๋ blocking ์ํ์ ์๊ฒ ๋๋ค.
์ค๋ ๋์๋ฅผ ๋๋ ค I/O-bound ๋ฌธ์ ๋ฅผ ํํผํ๋ค๊ณ ํด๋, ์ด๋ ๊ฒ ์ง์ Hdd์ ์ฝ๊ณ /์ฐ๋ ๋ฐฉ์์ ๊ธ๋ฐฉ ํ๊ณ์ ๋ถ๋ชํ ๊ฒ์ด๋ค. ์๋ํ๋ฉด Java์ ์ค๋ ๋๋ ๋ง์ฐฌ๊ฐ์ง๋ก JNI๋ฅผ ํธ์ถํด OS์ ์ค๋ ๋๋ฅผ ์ด์ฉํ๋๋ฐ, ์ค๋ ๋๊ฐ ๋์ด๋ ์๋ก I/O ์์ (I/O-bound) ๊ฐ์ context switching์ด ์์ฃผ ๋ฐ์ํด ์ ์ฒด์ ์ธ ํผํฌ๋จผ์ค๊ฐ ๋จ์ด์ง๋ค.
๋ฐ์ดํฐ ์ ์ถ๋ ฅ ์๊ฐ์ ์ค์ด๋ ๊ฒ์ ํต์ฌ์ hdd์ ์ ๊ทผํ๋ ํ์๋ฅผ ์ต๋ํ ์ค์ด๋ ๊ฒ์ด๋ค.
Java 21์์ ์ค๋ ๋์ ์ปจํ ์คํธ ์ค์์นญ ๋น์ฉ์ ์ต์ํํ๊ธฐ ์ํด virtual thread ๊ฐ ๋์ ๋์๋ค.
๐ก HDD๋ ๋์คํฌ์ ๊ธฐ๋ก๋ ์์ฑ์ ์ธ๊ธฐ๊ฐ 1๋ ์ 1% ๊ฐ์ํ๊ณ , SSD๋ ์ ์์ด ์ธ๊ฐ๋์ง ์์ ์ํ์์๋ ์ ์ ๋์ค์ ๋ฅ๋ก ์ธํด ๋น ๋ฅด๋ฉด 1๋ ์ด๋ด์ ๋ฐ์ดํฐ ์์ค์ด ์ผ์ด๋ ์ ์๋ค๊ณ ํ๋ค.
๋ฒํผ(buffer) ์ฌ์ฉ
Hdd ์ ์ง์ ์ฝ๊ณ ์ฐ๋ JNI(Java Native Interface) ํธ์ถ ๋น๋๋ฅผ ์ต๋ํ ์ค์ด๊ธฐ ์ํด ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ์ผ์ ํ ํฌ๊ธฐ์ ๋ฒํผ์ ๋ด์ ๋์๋ค๊ฐ ๋ฒํผ๊ฐ ๊ฐ๋ ์ฐจ๋ฉด Hdd ์ writeํ๊ฑฐ๋ read ํ๋๋ก ์์ ํ๋ค.
๊ธฐ์กด์ ์ฌ์ฉํ๋ DataInputStream
๊ณผ DataOutputStream
์ ๊ฐ๊ฐ ์์ํด ๋ฒํผ ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋ ํด๋์ค๋ฅผ ๋ง๋ ๋ค.
buffer์ ๋ชจ์๋ค๊ฐ ํ๋ฒ์ ๋ด๋ณด๋ธ๋ค.
BufferedDataInputStream
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class BufferedDataInputStream extends DataInputStream {
private final byte[] buf = new byte[8192];
int size; // ์ฝ์ ๋ฐ์ดํธ ์
int cursor; // ๋ฒํผ ์ธ๋ฑ์ค
public BufferedDataInputStream(String name) throws FileNotFoundException {
super(name);
}
@Override
public int read() throws IOException {
if (cursor == size) {
cursor = 0;
size = super.read(buf); // ์ฝ์ ๋ฐ์ดํธ ์๋ฅผ ๋ฆฌํดํ๋ค.
if (size == -1) {
return -1; // ์ฝ์ ๋ฐ์ดํฐ๊ฐ ์๋ค.
}
}
return buf[cursor++] & 0xFF; // sign-magnitude ๋ฐฉ์์ผ๋ก ์ฝ์ด์ผ ํ๋ค.
// byte -> int ํ๋ณํ์ ์์๋ก ๋ฐ๋ ๊ฒฝ์ฐ๋ฅผ ์ํด `AND ๋นํธ ์ฐ์ฐ`ํ๋ค.
}
@Override
public int read(byte[] arr) throws IOException {
return read(arr, 0, arr.length);
}
@Override
public int read(byte[] arr, int off, int len) throws IOException {
for (int i = off, count = 0; count < len; count++, i++) {
int b = read();
if (b == -1) {
return count > 0 ? count : -1; // ์ฝ์ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด -1์ ๋ฆฌํดํด์ผํ๋ค.
}
arr[i] = (byte) b;
}
return len;
}
}
๋จผ์ ๋ฐ์ดํฐ๋ฅผ ์์๋ก ๋ด์๋ ๊ณต๊ฐ(buf
)์ ์ ์ธํ๋ค. ์ด๋ ๋ฐ์ดํฐ๋ฅผ ์ต๋ํ ๋ง์ด ๋ด๊ฒ ๋ค๊ณ ๋ฒํผ์ ํฌ๊ธฐ๋ฅผ ๋ฌด์ง๋ง์งํ๊ฒ ๋๋ฆฌ๋ฉด ์๋๋ค.
์๋ฒํ๋ก๊ทธ๋จ์ ์ฌ๋ฌ ์ฌ๋์ด ๋์์ ์ ์ํด ์ฌ์ฉํ๊ฒ ๋๋๋ฐ ๋ฒํผ์ ํฌ๊ธฐ๊ฐ ํฌ๋ฉด ๊ทธ๋งํผ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๋ง์์ง๋ค. (์ ์์ ์ * ๋ฒํผ size)
- `size = super.read(buf)`: ์ต์ด ๋ฉ์๋ ํธ์ถ ์ ๋ถ๋ชจ ํด๋์ค(
FileInputStream
)์read
๋ฉ์๋๋ฅผ ํตํด ๋ฒํผ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ค๊ณ , ์ค์ ๋ก ์ฝ์ ๋ฐ์ดํธ ์๋ฅผsize
๋ณ์์ ์ ์ฅํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ฝ์ ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด(EOF)size
์ -1์ ๋ฆฌํดํ๊ณ ์ด๋ฅผ ๊ทธ๋๋ก ๋ฆฌํดํ๋ฉด์ ๋ฉ์๋๋ฅผ ์ข ๋ฃํ๋ค. - `return buf[cursor++] & 0xFF`: ์ฝ์ ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด ํ์ฌ ์ปค์๊ฐ ์์นํ ๋ฒํผ์ ๊ฐ์ ๋ฐํํ๊ณ , ์ปค์๋ฅผ ์ฆ๊ฐ์ํจ๋ค.
์ด๋ ๋ฒํผ์ ๋ ํผ๋ฐ์ค ํ์
(byte)๊ณผ ๋ฉ์๋ ๋ฆฌํดํ์
(int) ๊ฐ์ ํ์
์ด ๋ฌธ์ ๊ฐ ๋๋ค.
byte๋ฅผ ์ฝ์ ํ int ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ ๋ ์ 3byte๊ฐ ๋น์ด์๋ ์ํ๊ฐ ๋๋๋ฐ ๋ง์ฝ ์ฝ์ด๋ค์ธ byte๊ฐ sign-magnitude ๋ฐฉ์์ ์ํด7f
(0111 1111)๋ฅผ ๋์ด๊ฐ๊ฒ ๋๋ฉด(๋งจ ์์๋ฆฌ๊ฐ 1์ด ๋๋ฉด) ์์๋ก ๊ฐ์ฃผํ๊ณ 2์ ๋ณด์๋ฅผ ์ทจํ๋ค. ์ด๋ ์ฐ๋ฆฌ๊ฐ ์ป๊ณ ์ ํ๋ ๋ฐ์ดํฐ๊ฐ ์๋ ๋ค๋ฅธ ๊ฐ์ด ๋๋ค. byte ๋ฅผ ์ฝ์ ๊ทธ๋๋ก ๋ฐํํ๊ธฐ ์ํดFF
(1111 1111)์&
์ฐ์ฐ์ ํ๊ฒ๋๋ฉด ์ ํจํ ๊ฐ์ด ๊ทธ๋๋ก ์ถ๋ ฅ๋๋ค.
BufferedDataOutputStream
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class BufferedDataOutputStream extends DataOutputStream {
private final byte[] buf = new byte[8192]; // 8kb
int size;
public BufferedDataOutputStream(String name) throws FileNotFoundException {
super(name);
}
@Override
public void write(int b) throws IOException {
if (size == buf.length) {
// ๋ฒํผ๊ฐ ๋ชจ๋ ์ฐผ๋ค๋ฉด, ๋ฒํผ์ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฅผ ํ์ผ๋ก ์ถ๋ ฅํ๋ค.
flush();
}
buf[size++] = (byte) b;
}
@Override
public void write(byte[] bytes) throws IOException {
for (byte b : bytes) {
if (size == buf.length) {
flush();
}
buf[size++] = b;
}
}
// ๋ฒํผ์ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฅผ ํ์ผ๋ก ์ถ๋ ฅํ๋ค.
public void flush() throws IOException {
super.write(buf, 0, size);
size = 0;
}
// try-with-resources ๊ตฌ๋ฌธ์์ ์๋ ํธ์ถ๋๋ ๋ฉ์๋์ด๋ค.
@Override
public void close() throws IOException {
// ์ถ๋ ฅ ์คํธ๋ฆผ์ ๋ซ๊ธฐ์ ์ ๋ฒํผ์ ๋จ์์๋ ๋ฐ์ดํฐ๋ฅผ ํ์ผ๋ก ์ถ๋ ฅํ๋ค.
flush();
super.close();
}
}
FileInputStream
์ write()
๋ฅผ ํธ์ถํด Hdd๋ก๋ถํฐ 1byte์ฉ ์ฝ์ด์ค๋ ๋ฐฉ์์ด ์๋๋ผ ๋ฒํผ์ ํ์ฌ ๋ฐ์ดํฐ๊ฐ ๋ค์ด์๋ ์ฌ์ด์ฆ ๋งํผ์ฉ ์ฝ๋๋ค.
ํธ์ถ๋ถ(App)์์๋ ์ธ์คํด์ค ๊ตฌํ๋ถ๋ง ๋ฐ๊ฟ์ฃผ๋ฉด ๋๋ค. ์ด์ wrapper class(DataOutputStream, DataInputStream ํด๋์ค
)์ ์ ๋ฌ๋๋ ์ธ์คํด์ค๋ write()
, read()
๋ฅผ ์ฌ์ ์ํด์ ๋ฒํผ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋ ์ธ์คํด์ค๊ฐ ๋๋ค.
๋ฒํผ๋ฅผ ์ฌ์ฉํ๋๋ก ๋ฉ์๋ ์ฌ์ ์
์ฑ๋ฅ ๋น๊ต
์์์ ๊ตฌํํ DataInputStream
๊ทธ๋ฆฌ๊ณ BufferedDataInputStream
ํ
์คํธ ์
๋ฐ์ดํฐ 400๋ง๊ฐ(72Mb) ๊ธฐ์ค
์ฝ๊ธฐ
- DataInputStream: 32.7์ด
- BufferedDataInputStream: 12.1์ด
์ฐ๊ธฐ
- DataOutputStream: 56.2์ด
- BufferedDataOutputStream: 0.4์ด
๋๊ธ๋จ๊ธฐ๊ธฐ