Publish:

ํƒœ๊ทธ: ,

์นดํ…Œ๊ณ ๋ฆฌ:

  • ์ด์ „ ๊ธ€์— ์ด์–ด์„œ ํŒŒ์ผ ์ž…์ถœ๋ ฅ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•ด๋ณธ๋‹ค.
  • ๋ฒ„ํผ(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์ดˆ

reference

๋ฐฉ๋ฌธํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๋Œ“๊ธ€,์ง€์ ,ํ”ผ๋“œ๋ฐฑ ์–ธ์ œ๋‚˜ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค๐Ÿ˜Š

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ