์ž๋ฐ”์—์„œ ํŒŒ์ผ์„ ๋‹ค์‹œ ์ฝ๋Š” ๋ฐฉ๋ฒ•: BufferedInputStream mark/reset ๋™์ž‘ ๋ถ„์„๊ณผ RandomAccessFile ํ™œ์šฉ

์ž๋ฐ”์—์„œ InputStream์„ ๋‹ค๋ฃจ๋‹ค ๋ณด๋ฉด ํŒŒ์ผ์˜ ํ—ค๋”๋งŒ ์‚ด์ง ์ฝ์–ด ํŒŒ์ผ์˜ ํ˜•์‹์„ ํ™•์ธํ•œ ๋’ค ๋‹ค์‹œ ์ฒ˜์Œ๋ถ€ํ„ฐ ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ์ƒ๊ธฐ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์ด ๋•Œ ์ง๊ด€์ ์œผ๋กœ reset() ๋ฉ”์„œ๋“œ๋ฅผ ๋– ์˜ฌ๋ฆฌ์ง€๋งŒ ๋ง‰์ƒ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด IOException์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์ŠคํŠธ๋ฆผ์—์„œ ์ด์ „ ์œ„์น˜๋กœ ๋Œ์•„๊ฐ€๋Š” ๋ฐฉ๋ฒ•๊ณผ ํ•จ๊ป˜ BufferedInputStream์˜ mark/reset/fill์˜ ๋™์ž‘์— ๋Œ€ํ•ด์„œ ๋ถ„์„ํ•˜๊ณ  RandomAccessFile์˜ ์‚ฌ์šฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

InputStream

์ž๋ฐ”์˜ java.io.InputStream์€ ๋ชจ๋“  ๋ฐ”์ดํŠธ ์ž…๋ ฅ ์ŠคํŠธ๋ฆผ์˜ ์ตœ์ƒ์œ„ ์ถ”์ƒ ํด๋ž˜์Šค๋‹ค. InputStream์€ read() ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋˜๋Œ๋ฆฌ๋Š” ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด์„œ๋Š” ๋งค์šฐ ๋ณด์ˆ˜์ ์ด๋‹ค. ์ด์œ ๋Š” ์ŠคํŠธ๋ฆผ์˜ Source๊ฐ€ ๋‹ค์–‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํŒŒ์ผ๊ณผ ๊ฐ™์ด ๋ฐ์ดํ„ฐ๊ฐ€ ๊ณ ์ •๋œ ์ €์žฅ์†Œ์— ์žˆ๋‹ค๋ฉด ๋˜๋Œ์•„๊ฐ€๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ํ‚ค๋ณด๋“œ ์ž…๋ ฅ์ด๋‚˜ ๋„คํŠธ์›Œํฌ ์†Œ์ผ“๊ณผ ๊ฐ™์ด ํœ˜๋ฐœ์„ฑ์ด ๊ฐ•ํ•œ ์ŠคํŠธ๋ฆผ์˜ ๊ฒฝ์šฐ์—๋Š” ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๋˜๋Œ์•„ ๊ฐ€๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ตœ์ƒ์œ„ ์ถ”์ƒ ํด๋ž˜์Šค์ธ InputStream์€ ๋ชจ๋“  ์ŠคํŠธ๋ฆผ์„ ๊ณ ๋ คํ•œ ์ถ”์ƒ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ์ ์œผ๋กœ ๋˜๋Œ๋ฆฌ๋Š” ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜์ง€ ์•Š๋„๋ก ํ•˜๊ณ  ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ตฌํ˜„์ฒด์—๊ฒŒ ๋˜๋Œ๋ฆฌ๋Š” ๊ธฐ๋Šฅ์„ Overwrite ํ•˜๋„๋ก ํ•œ๋‹ค.

markSupported – ๋˜๋Œ๋ฆด ์ˆ˜ ์žˆ์–ด?

reset() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ŠคํŠธ๋ฆผ์„ ์ด์ „ ์ง€์ ์œผ๋กœ ๋˜๋Œ๋ฆฌ๋ ค ํ•  ๋•Œ ๊ฐ€์žฅ ๋จผ์ € ํ•ด์•ผ ํ•  ๊ฒƒ์€ ํ•ด๋‹น ์ŠคํŠธ๋ฆผ ์ธ์Šคํ„ด์Šค๊ฐ€ reset() ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ”๋กœ markSupported ๋ฉ”์„œ๋“œ๋‹ค.
์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ์ŠคํŠธ๋ฆผ ์ธ์Šคํ„ด์Šค์˜ markSupported ํ˜ธ์ถœ ๊ฒฐ๊ณผ true์ธ ๊ฒƒ์€ ๋˜๋Œ๋ฆฌ๊ธฐ๋ฅผ ์ง€์›ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋งŒ์•ฝ markSupported๊ฐ€ false๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ŠคํŠธ๋ฆผ ์ธ์Šคํ„ด์Šค์— mark๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์•„๋ฌด์ผ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š๊ณ , reset์„ ํ˜ธ์ถœํ•˜๋ฉดIOException์ด ๋ฐœ์ƒํ•œ๋‹ค.

public class StreamTest {
    private File file = new File("test.txt");
    @BeforeEach
    void setUp() {
        if (file.exists()) {
            file.delete();
        }

        // ํ…Œ์ŠคํŠธ์šฉ ํŒŒ์ผ ์ƒ์„ฑ
        try ( FileOutputStream fos = new FileOutputStream(file)) {
            fos.write("Hello Java IO".getBytes());
        } catch ( IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    void file_input_stream_test() {
        // FileInputStream์œผ๋กœ ์ฝ๊ธฐ ์‹œ๋„
        try ( InputStream is = new FileInputStream(file)) {
            // 1. mark/reset ์ง€์› ์—ฌ๋ถ€ ํ™•์ธ
            // FileInputStream์€ ๋‚ด๋ถ€ ๋ฒ„ํผ๊ฐ€ ์—†์œผ๋ฏ€๋กœ false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
            boolean supported = is.markSupported();
            System.out.println("Mark Supported: " + supported); // ์ถœ๋ ฅ: false

            if (!supported) {
                System.out.println("์ด ์ŠคํŠธ๋ฆผ์€ mark/reset์„ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
            }

            // 2. ๊ฐ•์ œ๋กœ mark ํ˜ธ์ถœ (์ง€์›ํ•˜์ง€ ์•Š์•„๋„ ์˜ˆ์™ธ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ๋ฌด์‹œ๋จ)
            is.mark(100);

            // 3. 5๋ฐ”์ดํŠธ ์ฝ๊ธฐ ("Hello")
            byte[] buffer = new byte[5];
            is.read(buffer);
            System.out.println("Read Data: " + new String(buffer));

            // 4. reset ์‹œ๋„ -> IOException ๋ฐœ์ƒ
            try {
                is.reset();
            } catch (IOException e) {
                System.out.println("IOException, ์˜ˆ์ƒ๋œ ์—๋Ÿฌ: " + e.getMessage());
                // ์ถœ๋ ฅ: java.io.IOException: reset() not supported ๋“ฑ
            }

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

์ฝ”๋“œ ์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

Mark Supported: false
์ด ์ŠคํŠธ๋ฆผ์€ mark/reset์„ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
Read Data: Hello
IOException, ์˜ˆ์ƒ๋œ ์—๋Ÿฌ: mark/reset not supported
Plaintext

FileInputStream๊ณผ ๊ฐ™์€ ๊ธฐ๋ณธ์ ์ธ ๋…ธ๋“œ ์ŠคํŠธ๋ฆผ์€ ๋˜๋Œ๋ฆฌ๊ธฐ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋˜๋Œ๋ฆฌ๊ธฐ๋ฅผ ์œ„ํ•ด์„œ๋Š” ์ฝ์—ˆ๋˜ ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋”˜๊ฐ€์— ๊ธฐ์–ตํ•ด๋‘ฌ์•ผ ํ•˜๋Š”๋ฐ FileInputStream์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์ž๋งˆ์ž ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌํ•˜๊ณ  ์žŠ์–ด๋ฒ„๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

mark(int readlimit) ๊ณ„์•ฝ

mark ๋ฉ”์„œ๋“œ๋Š” ์‰ฝ๊ฒŒ ๋งํ•˜์ž๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋™์ž‘์„ ์ •์˜ํ•œ๋‹ค.

์ง€๊ธˆ ํ˜„์žฌ ์œ„์น˜์— ๋งˆํ‚น(mark)์„ ํ•ด๋‘๊ณ  ์•ž์œผ๋กœ ์ตœ๋Œ€ readlimit ๋ฐ”์ดํŠธ๋งŒํผ ๋” ์ฝ์„ ๋•Œ๊นŒ์ง€๋Š” mark๋ฅผ ์œ ์ง€ํ•ด์ค˜. ๋งŒ์•ฝ readlimit ๋ฐ”์ดํŠธ๋งŒํผ ๋” ์ฝ์œผ๋ฉด ๊ทธ ๋•Œ๋Š” mark๋ฅผ ์ œ๊ฑฐํ•ด๋„ ์ข‹์•„.

mark ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๋Š” ์ŠคํŠธ๋ฆผ (์˜ˆ. BufferedInputStream, ByteArrayInputStream)์„ ์‚ฌ์šฉํ•  ๋•Œ mark ๋ฉ”์„œ๋“œ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์ธ readlimit์˜ ์ •ํ™•ํ•œ ์˜๋ฏธ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • readlimit์€ “๋งˆํฌ(mark)ํ•œ ์œ„์น˜๋ฅผ ๋ฌดํšจํ™”ํ•˜์ง€ ์•Š๊ณ  ์•ž์œผ๋กœ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ๋ฐ”์ดํŠธ ์ˆ˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  • mark(100)์„ ํ˜ธ์ถœํ–ˆ๋‹ค๋ฉด ์ŠคํŠธ๋ฆผ์€ “์ตœ์†Œํ•œ 100๋ฐ”์ดํŠธ๋ฅผ ๋” ์ฝ์„ ๋•Œ๊นŒ์ง€๋Š” ํ˜„์žฌ ์œ„์น˜๋ฅผ ๊ธฐ์–ตํ•ด ์ฃผ๊ฒ ๋‹ค“๋ผ๊ณ  ์•ฝ์†ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

readlimit ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํ•„์š”ํ•œ ์ด์œ ๋Š” ๋ฉ”๋ชจ๋ฆฌ(Buffer) ๋•Œ๋ฌธ์ด๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ŠคํŠธ๋ฆผ์€ ํ•œ๋ฒˆ ์ฝ์€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ์–ตํ•˜์ง€ ์•Š์ง€๋งŒ markSupported๋ฅผ ์ง€์›ํ•˜๋Š” ๊ฒฝ์šฐ mark๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ˆœ๊ฐ„ ์ŠคํŠธ๋ฆผ ์ธ์Šคํ„ด์Šค๋Š” ํ˜„์žฌ ์œ„์น˜ ์ดํ›„ ๋“ค์–ด์˜ค๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋‚ด๋ถ€ ๋ฒ„ํผ์— ์ €์žฅํ•˜๋Š”๋ฐ ๋‚˜์ค‘์— reset์„ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ ์ €์žฅํ•ด๋‘” ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ๊บผ๋‚ด์˜ฌ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํ•˜์ง€๋งŒ ๋ฒ„ํผ ๋ฉ”๋ชจ๋ฆฌ ์ƒ์— ๋ฌดํ•œ์ • ๋ฐ์ดํ„ฐ๋ฅผ ์Œ“์•„๋‘˜ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— readlimit ๊ฐ’์œผ๋กœ ๋ฒ„ํผ์˜ ํฌ๊ธฐ๋ฅผ ์ œํ•œํ•˜๊ธฐ ์œ„ํ•ด์„œ๋‹ค.

๋‚ด๊ฐ€ ์–ผ๋งŒํผ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ์–ตํ•˜๊ณ  ์žˆ์–ด์•ผ ํ•ด?

readlimit์€ 100๋ฐ”์ดํŠธ๋ผ๊ณ  ํ•˜๋ฉด ์ŠคํŠธ๋ฆผ์€ 100๋ฐ”์ดํŠธ๊นŒ์ง€ ๋ฒ„ํผ์— ์ €์žฅํ•˜๊ณ  101๋ฐ”์ดํŠธ๋ฅผ ์ฝ๋Š” ์ˆœ๊ฐ„ ๊ณ„์•ฝ์€ ๊นจ์ง€๊ฒŒ ๋œ๋‹ค.

mark ๋ฉ”์„œ๋“œ์— readlimit์„ ์„ค์ •ํ•  ๋•Œ๋Š” ๊ฐ’์„ ๋„‰๋„‰ํ•˜๊ฒŒ ์žก๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•˜๋‹ค. readlimit์€ “์ตœ์†Œํ•œ ์ด๋งŒํผ์€ ๋ณด์žฅํ•ด๋ผ“๋ผ๋Š” ์˜๋ฏธ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ฝ์„ ๋ฐ”์ดํŠธ ์ˆ˜๋ณด๋‹ค ๋„‰๋„‰ํ•˜๊ฒŒ ์žก๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ๋งŒ์•ฝ readlimit์„ ์ดˆ๊ณผํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์€ ํ›„ reset์„ ํ˜ธ์ถœํ•˜๋ฉด IOException ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

ByteArrayInputStream

byte[] ๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ByteArrayInputStream์„ ์‚ดํŽด๋ณด์ž. markSupported๋ฅผ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— mark, reset์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.

@Test
void byte_array_input_stream_test() {
    String content = "header:byte array input stream test";
    byte[] data = content.getBytes();
    try ( ByteArrayInputStream bis = new ByteArrayInputStream(data) ) {
        // 'header' ๋ถ€๋ถ„๋งŒ ๋จผ์ € ์ฝ์–ด์„œ ํ™•์ธ
        byte[] buf = new byte[7];
        bis.read(buf);
        System.out.println("ํ—ค๋” ํ™•์ธ: " + new String(buf));

        // ํ˜„์žฌ ์œ„์น˜ ๋งˆํ‚น
        // ByteArrayInputStream์€ ์ด๋ฏธ ์†Œ์Šค ์ž์ฒด๊ฐ€ buffer ์—ญํ• ์„ ํ•˜๋ฏ€๋กœ
        // readlimit ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์ด ์˜๋ฏธ๊ฐ€ ์—†๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” 0์„ ์ž…๋ ฅํ–ˆ๋‹ค. (์‚ฌ์‹ค ์•„๋ฌด๊ฐ’์ด๋‚˜ ์ƒ๊ด€์ด ์—†์Œ)
        System.out.println("Marking!");
        // 'header:' ๋‹ค์Œ ๋ถ€๋ถ„์— marking
        bis.mark( 0 );
        // ๋‹ค์Œ 7byte read
        bis.read(buf);
        System.out.println("header ๋‹ค์Œ 7๋ฌธ์ž: " + new String(buf));

        // ์œ„์น˜ ๋ฆฌ์…‹
        System.out.println("Resetting!");
        bis.reset();

        byte[] allContents = bis.readAllBytes();
        System.out.println("๋‚ด์šฉ ์ „์ฒด: " + new String(allContents));
    }
    catch ( IOException e ) {
        // ByteArrayInputStream์—์„œ๋Š” ์‚ฌ์‹ค์ƒ IOException์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์ง€๋งŒ
        // InputStream ๊ทœ์•ฝ์ƒ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ์ •์˜๋Š” ํ•„์š”ํ•จ
        throw new RuntimeException( e );
    }
}
Java

์ฝ”๋“œ ์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

ํ—ค๋” ํ™•์ธ: header:
Marking!
header ๋‹ค์Œ 7๋ฌธ์ž: byte ar
Resetting!
๋‚ด์šฉ ์ „์ฒด: byte array input stream test
Plaintext
  • ๋จผ์ € ์ฒ˜์Œ 7byte์ฝ๋Š”๋‹ค. (‘header:’)
  • ํ˜„์žฌ ์œ„์น˜์— marking ํ•œ๋‹ค. (ByteArrayInputStream์€ ์†Œ์Šค ์ž์ฒด๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ์ƒ์— ์žˆ๊ธฐ ๋•Œ๋ฌธ์— readlimit ๊ฐ’์€ ์˜๋ฏธ์—†๋‹ค)
  • ๊ทธ ๋‹ค์Œ 7byte๋ฅผ ์ฝ๋Š”๋‹ค. (‘byte ar’)
  • reset()์„ ํ˜ธ์ถœํ•˜์—ฌ ์œ„์น˜ ํฌ์ธํ„ฐ๋ฅผ marking ํ–ˆ๋˜ ์ž๋ฆฌ๋กœ ์˜ฎ๊ธด๋‹ค.
  • ์ „์ฒด๋ฅผ ์ฝ๋Š”๋‹ค. -> marking ํ–ˆ๋˜ ์œ„์น˜๋ถ€ํ„ฐ ๋๊นŒ์ง€ ์ฝ๋Š”๋‹ค. (‘byte array input stream test’)

BufferedInputStream

BufferedInputStream ์—ญ์‹œ markSupported๋ฅผ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— mark, reset์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ByteArrayInputStream๊ณผ ๋‹ฌ๋ฆฌ BufferedInputStream์˜ mark readlimit ๊ฐ’์€ ์ค‘์š”ํ•˜๋‹ค. ์ฐธ๊ณ ๋กœ BufferedInputStream์˜ ๋””ํดํŠธ ๋ฒ„ํผ ํฌ๊ธฐ๋Š” 8192byte(8KB)๋‹ค. BufferedInputStream์˜ ๋ฒ„ํผ ํฌ๊ธฐ๋Š” ์ƒ์„ฑ์ž์—์„œ ์ง€์ •ํ•˜์—ฌ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ณ„๋„๋กœ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ๋””ํดํŠธ ์‚ฌ์ด์ฆˆ๊ฐ€ ์ ์šฉ๋œ๋‹ค.

public class StreamTest {
    private File file = new File("test.txt");
    @BeforeEach
    void setUp() {
        if (file.exists()) {
            file.delete();
        }

        // ํ…Œ์ŠคํŠธ์šฉ ํŒŒ์ผ ์ƒ์„ฑ
        try ( FileOutputStream fos = new FileOutputStream(file)) {
            fos.write("header:buffered input stream test".getBytes());
        } catch ( IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    void buffered_input_stream_test() {
        try ( BufferedInputStream bis = new BufferedInputStream( new FileInputStream( file ) )) {
            // ์ฒ˜์Œ 7byte read
            byte[] buf = new byte[7];
            bis.read(buf);
            System.out.println("ํ—ค๋” ํ™•์ธ: " + new String(buf));
            // ์ŠคํŠธ๋ฆผ์—์„œ ์ฝ์–ด๋“ค์ผ ์ˆ˜ ์žˆ๋Š” ๋‚จ์€ byte ๋งŒํผ readlimit์œผ๋กœ ์ ์šฉํ–ˆ๋‹ค.
            // ๋””ํดํŠธ ๋ฒ„ํผ ํฌ๊ธฐ๊ฐ€ 8192 byte ์ด๋ฏ€๋กœ 8192 byte๋ฅผ ๋„˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
            int available = bis.available();
            if ( available > 8192 ) {
                available = 8192;
            }

            // ํ˜„์žฌ ์œ„์น˜ Marking!
            System.out.println("Marking!");
            bis.mark( available );

            // ๋‹ค์Œ 7byte read
            bis.read(buf);
            System.out.println("header ๋‹ค์Œ 7๋ฌธ์ž: " + new String(buf));

            // ์œ„์น˜ ๋ฆฌ์…‹
            System.out.println("Resetting!");
            bis.reset();

            byte[] allContents = bis.readAllBytes();
            System.out.println("๋‚ด์šฉ ์ „์ฒด: " + new String(allContents));
        }
        catch ( IOException e ) {
            throw new RuntimeException( e );
        }
    }
  }
Java

์ƒ˜ํ”Œ ์ฝ”๋“œ๋Š” BufferedInputStream์˜ ๋””ํดํŠธ ๋ฒ„ํผ ํฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.
์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

ํ—ค๋” ํ™•์ธ: header:
Marking!
header ๋‹ค์Œ 7๋ฌธ์ž: buffere
Resetting!
๋‚ด์šฉ ์ „์ฒด: buffered input stream test
Plaintext

BufferedInputStream fill() ๋™์ž‘

mark(readlimit)์„ ์ง€์ •ํ•œ ์ดํ›„์— BufferedInputStream ๋ฒ„ํผ์˜ ๋งˆ์ง€๋ง‰๊นŒ์ง€ ์ฝ๊ฒŒ๋˜๋ฉด fill() ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š”๋ฐ ๋‚ด๋ถ€ ๋™์ž‘์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์Šฌ๋ผ์ด๋”ฉ : ์•ž์ชฝ ๊ณต๊ฐ„ ์žฌํ™œ์šฉ

marking๋œ ์œ„์น˜(๋ฒ„ํผ๋‚ด ์ธ๋ฑ์Šค ์œ„์น˜)๊ฐ€ > 0 ๊ฒฝ์šฐ์— ์Šฌ๋ผ์ด๋”ฉ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค.

if (markpos > 0) {  /* can throw away early part of the buffer */
    int sz = pos - markpos;
    System.arraycopy(buffer, markpos, buffer, 0, sz);
    pos = sz;
    markpos = 0;
}
Java

์ฆ‰ marking๋œ ์œ„์น˜๋ถ€ํ„ฐ ๋ฒ„ํผ์˜ ๋๊นŒ์ง€ ๋ณต์‚ฌํ•˜์—ฌ ๋ฒ„ํผ์˜ ๋งจ ์•ž์—์„œ๋ถ€ํ„ฐ ๋ฎ์–ด์“ฐ๊ณ  marking ์œ„์น˜๋ฅผ 0์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.
์ด ๋•Œ๋Š” marking ๋ฌดํšจํ™”๋ฅผ ํ•˜์ง€ ์•Š๋Š”๋‹ค.
(marking ๋œ ์œ„์น˜๋ฅผ ๋ฌดํšจํ™” ํ•œ๋‹ค๋Š” ๊ฒƒ์€ marking๋œ ์œ„์น˜ ๊ฐ’์„ -1๋กœ ์„ค์ •ํ•˜์—ฌ mark๋ฅผ ์—†์—ˆ๋˜ ์ผ๋กœ ๋งŒ๋“œ๋Š” ๋™์ž‘์„ ๋งํ•œ๋‹ค.)

์œ„ ์ƒ˜ํ”Œ ์ฝ”๋“œ๋ฅผ ์•ฝ๊ฐ„ ์ˆ˜์ •ํ•˜์—ฌ ํ™•์ธํ•ด ๋ณด์ž.

@Test
void buffered_input_stream_test() {
    try ( BufferedInputStream bis = new BufferedInputStream( new FileInputStream( file ), 10 )) {
        // ์ฒ˜์Œ 7byte read
        byte[] buf = new byte[7];
        bis.read(buf);
        System.out.println("ํ—ค๋” ํ™•์ธ: " + new String(buf));

        // ํ˜„์žฌ ์œ„์น˜ Marking! (readlimit: 5)
        System.out.println("Marking!");
        bis.mark( 5 );

        // ๋‹ค์Œ 7byte read
        bis.read(buf);
        System.out.println("header ๋‹ค์Œ 7๋ฌธ์ž: " + new String(buf));

        // ์œ„์น˜ ๋ฆฌ์…‹
        System.out.println("Resetting!");
        bis.reset();

        byte[] allContents = bis.readAllBytes();
        System.out.println("๋‚ด์šฉ ์ „์ฒด: " + new String(allContents));
    }
    catch ( IOException e ) {
        throw new RuntimeException( e );
    }
}
Java

ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด BufferedInputStream์˜ ๋ฒ„ํผ์˜ ํฌ๊ธฐ๋ฅผ 10์œผ๋กœ ์ฃผ์–ด ๋ฒ„ํผ์˜ ๋๊นŒ์ง€ ์ฝ๋„๋ก ํ•˜์—ฌ fill์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.
์ฒ˜์Œ read ํ˜ธ์ถœ ํ›„ ๋ฒ„ํผ์˜ ์ƒํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

header:buf (10byte)
       ^
       |
       marking (ํ˜„์žฌ pos)
Java

์ดํ›„ mark(5) ์ง€์ • ํ›„ 7byte๋ฅผ ์ฝ์€ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ๋ฒ„ํผ์˜ marking ์œ„์น˜ ๋ถ€ํ„ฐ ์ฝ์€ 3byte(‘buf’)๊ฐ€ ๋ฒ„ํผ์˜ 0๋ฒˆ์งธ ์œ„์น˜๋กœ overwrite ๋˜๊ณ  marking ์œ„์น˜๋ฅผ 0์œผ๋กœ ๋ณ€๊ฒฝ ํ›„ ๋ฒ„ํผ์˜ ๋‚˜๋จธ์ง€ 7byte๋Š” ํŒŒ์ผ๋กœ ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์„œ ์ฑ„์šด๋‹ค.

buffered i
^
|
marking ์œ„์น˜
Java

์ดํ›„ reset()์„ ํ˜ธ์ถœํ•˜๋ฉด ์ •์ƒ์ ์œผ๋กœ marking ์œ„์น˜๋กœ ๋Œ์•„๊ฐ€ ๋‹ค์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ฒŒ ๋œ๋‹ค. (marking ๋ฌดํšจํ™”๊ฐ€ ๋˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ)

Marking ๋ฌดํšจํ™”

marking๋œ ์œ„์น˜๊ฐ€ > 0์ด ์•„๋‹Œ ๊ฒฝ์šฐ BufferedInputStream์˜ ๋ฒ„ํผ์˜ ํฌ๊ธฐ๊ฐ€ readlimit ๊ฐ’๋ณด๋‹ค ๋” ํฐ ๊ฒฝ์šฐ Marking์€ ๋ฌดํšจํ™” ๋œ๋‹ค. (markpos == 0 && buffer.length >= marklimit)

else if (buffer.length >= marklimit) {
    markpos = -1;   /* buffer got too big, invalidate mark */
    pos = 0;        /* drop buffer contents */
}
Java

์ด์œ ๋Š” markpos == 0 ์ธ ๊ฒฝ์šฐ (์Šฌ๋ผ์ด๋”ฉ ์กฐ๊ฑด์ด ์•„๋‹ˆ๋ฏ€๋กœ > 0) ์ธ๋ฐ marking ์œ„์น˜๊ฐ€ 0์ด๋ฏ€๋กœ ๋ฒ„ํผ์˜ 0๋ฒˆ์งธ ์œ„์น˜์— ๋ฎ์–ด์‘ฌ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” markpost๋ฅผ -1๋กœ ์ง€์ •ํ•˜์—ฌ marking ๋ฌดํšจํ™”๋ฅผ ์„ ์–ธํ•œ๋‹ค.
(์ดํ›„ reset() ํ˜ธ์ถœ์‹œ IOException์˜ ๋ฐœ์ƒ ์›์ธ)

์ƒ˜ํ”Œ ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•˜์—ฌ ํ™•์ธํ•ด ๋ณด์ž.

@Test
void buffered_input_stream_exception_test() {
    try ( BufferedInputStream bis = new BufferedInputStream( new FileInputStream( file ), 10 )) {
        // markpos == 0, readlimit(marklimit) == 5, buffer size == 10
        bis.mark( 5 );

        // 7 byte read
        byte[] buf = new byte[7];
        bis.read(buf);
        System.out.println("ํ—ค๋” ํ™•์ธ: " + new String(buf));

        // ์—ฌ๊ธฐ์„œ fill ํ˜ธ์ถœ ๋ฐœ์ƒ (markpos == 0 && buffer size >= readlimit) ์ด๋ฏ€๋กœ marking ๋ฌดํšจํ™” ๋ฐœ์ƒ
        byte[] allContents = bis.readAllBytes();
        System.out.println("๋‚˜๋จธ์ง€ ์ฝ์Œ: " + new String(allContents));

        // ์œ„์น˜ ๋ฆฌ์…‹ (marking ๋ฌดํšจํ™”๋กœ ์˜ˆ์™ธ ๋ฐœ์ƒํ•จ!!!!)
        System.out.println("Resetting!");
        bis.reset();
    }
    catch ( IOException e ) {
        throw new RuntimeException( e );
    }
}
Java

์ฝ๊ธฐ ์ „์— mark๋ฅผ ์ง€์ •ํ•˜์—ฌ marking ์œ„์น˜๋ฅผ 0์œผ๋กœ ์„ค์ •ํ•˜์˜€๋‹ค. ๋ฒ„ํผ ํฌ๊ธฐ๋Š” 10byte, readlimit์€ 5byte๋‹ค.
์ฒซ๋ฒˆ์งธ 7 byte๋ฅผ ์ฝ์€ ํ›„ ๋‘๋ฒˆ์งธ readAllBytes()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋‚˜๋จธ์ง€๋ฅผ ๋ชจ๋‘ ์ฝ๋„๋ก ํ•˜์˜€๋‹ค. ์ด ๊ณผ์ •์—์„œ ๋ฒ„ํผ์˜ ๋๊นŒ์ง€ ์ฝ์–ด์•ผ ํ•˜๋ฏ€๋กœ fill()์ด ๋ฐœ์ƒํ•˜๊ณ  (markpos == 0 && buffer.length >= marklimit) ์กฐ๊ฑด์— ์˜ํ•ด์„œ marking์ด ๋ฌดํ•ดํ™” ๋˜์–ด -1๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.
์ดํ›„ reset()์„ ํ˜ธ์ถœํ•˜๋ฉด marking์ด ๋ฌดํ•ดํ™” ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋Œ์•„๊ฐˆ ์ˆ˜ ์—†์–ด์„œ IOException ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

ํ—ค๋” ํ™•์ธ: header:
๋‚˜๋จธ์ง€ ์ฝ์Œ: buffered input stream test
Resetting!

java.io.IOException: Resetting to invalid mark
...
...
Plaintext

๋ฒ„ํผ ํ™•์žฅ (Growing)

์Šฌ๋ผ์ด๋”ฉ๊ณผ Marking ๋ฌดํšจํ™” ์กฐ๊ฑด์— ํ•ด๋‹น๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ BufferedInputStream์˜ ํฌ๊ธฐ๋ฅผ ๋™์ ์œผ๋กœ ํ™•์žฅํ•œ๋‹ค.
(markpos == 0 && buffer.length < marklimit)

else {            /* grow buffer */
    int nsz = ArraysSupport.newLength(pos,
            1,  /* minimum growth */
            pos /* preferred growth */);
    if (nsz > marklimit)
        nsz = marklimit;
    byte[] nbuf = new byte[nsz];
    System.arraycopy(buffer, 0, nbuf, 0, pos);
    if (!U.compareAndSetReference(this, BUF_OFFSET, buffer, nbuf)) {
        // Can't replace buf if there was an async close.
        // Note: This would need to be changed if fill()
        // is ever made accessible to multiple threads.
        // But for now, the only way CAS can fail is via close.
        // assert buf == null;
        throw new IOException("Stream closed");
    }
    buffer = nbuf;
}
Java

๋ฒ„ํผ์˜ ๋งจ ์•ž์œผ๋กœ ๋ฎ์–ด์“ธ ์ˆ˜๋Š” ์—†์ง€๋งŒ (markpos == 0์ด๋ฏ€๋กœ) ์‚ฌ์šฉ์ž๊ฐ€ readlimit์„ bufferํฌ๊ธฐ ๋ณด๋‹ค ๋” ํฌ๊ฒŒ ์ง€์ •ํ–ˆ์œผ๋‹ˆ๊นŒ ๋” ๋Š˜๋ ค์ฃผ์ž๋Š” ์˜๋ฏธ์˜ ๋™์ž‘์ด๋‹ค. ์ด ๊ฒฝ์šฐ ์—ญ์‹œ marking ๋ฌดํšจํ™”๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.
marking ๋ฌดํšจํ™” ์ƒ˜ํ”Œ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ ๋™์ž‘์„ ํ™•์ธํ•ด๋ณด์ž.

@Test
void buffered_input_stream_no_exception_test() {
    try ( BufferedInputStream bis = new BufferedInputStream( new FileInputStream( file ), 10 )) {
        // markpos == 0, readlimit == 40, buffer size == 10
        bis.mark(40);

        // 7 byte read
        byte[] buf = new byte[7];
        bis.read(buf);
        System.out.println("ํ—ค๋” ํ™•์ธ: " + new String(buf));

        // ์—ฌ๊ธฐ์„œ fill ํ˜ธ์ถœ ๋ฐœ์ƒ (markpos == 0 && buffer size < readlimit) ์ด๋ฏ€๋กœ buffer ํ™•์žฅ์ด ์ผ์–ด๋‚œ๋‹ค.
        // readlimit size ๋งŒํผ.
        byte[] allContents = bis.readAllBytes();
        System.out.println("๋‚˜๋จธ์ง€ ์ฝ์Œ: " + new String(allContents));
        
        // ์œ„์น˜ ๋ฆฌ์…‹
        System.out.println("try Resetting!");
        bis.reset();
        System.out.println("Success Resetting!");
    }
    catch ( IOException e ) {
        throw new RuntimeException( e );
    }
}
Java

์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

ํ—ค๋” ํ™•์ธ: header:
๋‚˜๋จธ์ง€ ์ฝ์Œ: buffered input stream test
try Resetting!
Success Resetting!
Plaintext

๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ธฐ ์ „์— mark(40)์„ ์ง€์ •ํ•˜์—ฌ markpos = 0, readlimit(marklimit) = 40์ด ๋˜๋„๋ก ํ–ˆ๋‹ค. (buffer size = 10)
๋‘๋ฒˆ์งธ readAllBytes() ํ˜ธ์ถœ์‹œ ์—ญ์‹œ fill() ํ˜ธ์ถœ์ด ์ผ์–ด๋‚˜๋ฉฐ (markpos == 0 && buffer.length < marklimit) ์กฐ๊ฑด์— ๋”ฐ๋ผ์„œ ๋ฒ„ํผ์˜ ํฌ๊ธฐ๊ฐ€ 10 -> 40byte๋กœ ํ™•์žฅ ๋œ๋‹ค.
์ฒ˜์Œ read() ํ˜ธ์ถœ ์ดํ›„ ๋ฒ„ํผ ์ƒํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

[104, 101, 97, 100, 101, 114, 58, 98, 117, 102] --> 10byte
Java

๋‘๋ฒˆ์งธ readAllBytes() ํ˜ธ์ถœ ์ดํ›„ ๋ฒ„ํผ ์ƒํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

[104, 101, 97, 100, 101, 114, 58, 98, 117, 102, 102, 101, 114, 101, 100, 32, 105, 110, 112, 117, 116, 32, 115, 116, 114, 101, 97, 109, 32, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0] --> 40byte
Java

๋™์ ์œผ๋กœ ๋ฒ„ํผ์˜ ํฌ๊ธฐ๊ฐ€ readlimit๋งŒํผ ํ™•์žฅ๋˜๋ฉด์„œ marking ๋ฌดํšจํ™”๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

๊ฒฐ๋ก ์ ์œผ๋กœ reset() ํ˜ธ์ถœ์‹œ marking์ด ๋ฌดํšจํ™” ๋œ ์ƒํƒœ๋ฉด IOException ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”๋ฐ marking์ด ๋ฌดํšจํ™” ๋˜๋Š” ์กฐ๊ฑด์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

marking์ด ๋ฌดํšจํ™” ๋˜๋Š” ์กฐ๊ฑด (markpos = -1)

๋ฒ„ํผ์˜ ๋๊นŒ์ง€ ์ฝ๊ฒŒ ๋˜๋ฉด fill ๋™์ž‘์ด ๋ฐœ์ƒ
marking ์œ„์น˜๊ฐ€ ๋ฒ„ํผ์˜ 0 ์œ„์น˜๊ณ  buffer์˜ ํฌ๊ธฐ๊ฐ€ readlimt๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์€ ๊ฒฝ์šฐ
(markpos == 0 && buffer.length < marklimit)

RandomAccessFile

InputStream์ด ์ˆœ์ฐจ์ ์ธ ๋ฐ์ดํŠธ ํ๋ฆ„์„ ๋‹ค๋ฃฌ๋‹ค๋ฉด RandomAccessFile์€ ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ ๋ณธ์งˆ์ ์ธ ํŠน์„ฑ์ธ ๋žœ๋ค ์ ‘๊ทผ์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๋‹ค.
RandomAccessFile์€ InputStream์ด๋‚˜ OutputStream์„ ์ƒ์†๋ฐ›์ง€ ์•Š๋Š”๋‹ค. ๋Œ€์‹  DataInput๊ณผ DataOutput ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ชจ๋‘ ๊ตฌํ˜„ํ•œ๋‹ค. ์ด๋Š” RandomAccessFile์€ ํŒŒ์ผ์„ ์ฝ๊ณ  ์“ฐ๋Š” ์–‘๋ฐฉํ–ฅ ํ†ต๋กœ์ž„์„ ์˜๋ฏธํ•œ๋‹ค.
RandomAccessFile์€ ํŒŒ์ผ ๋ฐ์ดํ„ฐ๋ฅผ ๋งˆ์น˜ ๊ฑฐ๋Œ€ํ•œ ๋ฐ”์ดํŠธ ๋ฐฐ์—ด ์ฒ˜๋Ÿผ ์ทจ๊ธ‰ํ•˜๋Š”๋ฐ ๋ฐฐ์—ด์˜ ์ธ๋ฑ์Šค์— ์ ‘๊ทผํ•˜๋“ฏ์ด ํŒŒ์ผ์˜ ์ž„์˜์˜ ์œ„์น˜๋กœ ์ปค์„œ(File Pointer)๋ฅผ ์ด๋™ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

ํ•ต์‹ฌ ๋ฉ”์นด๋‹ˆ์ฆ˜

RandomAccessFile์˜ ๋ชจ๋“  ๋™์ž‘์€ ํŒŒ์ผ ํฌ์ธํ„ฐ๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค.

  • getFilePointer(): ํ˜„์žฌ ์ปค์„œ์˜ ์œ„์น˜(๋ฐ”์ดํŠธ ์˜คํ”„์…‹)์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • seek(long pos): ์ปค์„œ๋ฅผ ํŒŒ์ผ์˜ pos ์œ„์น˜๋กœ ์ด๋™์‹œํ‚จ๋‹ค.
  • length(): ํŒŒ์ผ์˜ ์ „์ฒด ํฌ๊ธฐ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

seek() ๋ฉ”์„œ๋“œ๋Š” ์šด์˜์ฒด์ œ์˜ ์‹œ์Šคํ…œ ์ฝœ(ex. lseek())์— ์ง์ ‘ ๋งคํ•‘๋œ๋‹ค. ์ด๋Š” ๋งค์šฐ ๊ฐ•๋ ฅํ•˜์ง€๋งŒ OS๋ ˆ๋ฒจ์˜ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์ด ์กด์žฌํ•œ๋‹ค. BufferedInputStream์˜ reset()๊ณผ RandomAccessFile์˜ seek()์€ ์ด์ „ ์œ„์น˜๋กœ ๋Œ์•„๊ฐ„๋‹ค๋Š” ๊ฒฐ๊ณผ๋Š” ๊ฐ™์ง€๋งŒ ๋™์ž‘ ๋ฐฉ์‹์—๋Š” ํฐ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

BufferedInputStream (reset)RandomAccessFile (seek)
๋™์ž‘์›๋ฆฌ๋ฉ”๋ชจ๋ฆฌ ์ƒ์˜ ๋ฐฐ์—ด ์ธ๋ฑ์Šค๋งŒ ๋ณ€๊ฒฝOS์—๊ฒŒ ํŒŒ์ผ ์˜คํ”„์…‹ ๋ณ€๊ฒฝ ์š”์ฒญ (system call)
์†๋„๋งค์šฐ ๋น ๋ฆ„ (๋‚˜๋…ธ์ดˆ)์ƒ๋Œ€์ ์œผ๋กœ ๋А๋ฆผ (๋ฐ€๋ฆฌ์ดˆ ~ ๋งˆ์ดํฌ๋กœ์ดˆ)
๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋†’์Œ(๋˜๋Œ์•„๊ฐˆ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ํž™ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ)๋งค์šฐ ๋‚ฎ์Œ(๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•˜์ง€ ์•Š์Œ)
๋ฐ์ดํ„ฐ ์†Œ์ŠคํŒŒ์ผ, ๋„คํŠธ์›Œํฌ, ๋ฉ”๋ชจ๋ฆฌ๋“ฑ ๋ชจ๋“  ์ŠคํŠธ๋ฆผ์˜ค์ง ๋กœ์ปฌ ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ ํŒŒ์ผ๋งŒ ๊ฐ€๋Šฅ

RandomAccessFile์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒ„ํผ์— ๋‹ด์•„๋‘๊ณ  ์ด๋™ํ•˜์ง€ ์•Š๊ณ  ์‹œ์Šคํ…œ ์ฝœ์„ ์ด์šฉํ•˜์—ฌ ์œ„์น˜๋ฅผ ์ด๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ์—์„œ ์ž„์˜์˜ ์œ„์น˜๋กœ ๋˜๋Œ์•„๊ฐ€์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

์•„๋ž˜ ์ƒ˜ํ”Œ ์ฝ”๋“œ๋Š” ํŒŒ์ผ์˜ ๋งˆ์ง€๋ง‰ ์ง€์ •๋œ n byte๋งŒํผ ์ฝ๋Š” ์ฝ”๋“œ๋‹ค. ์ฒ˜์Œ ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ํ•„์š” ์—†์ด ์ปค์„œ๋ฅผ ๋ฐ”๋กœ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์œผ๋กœ ์ด๋™ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.

@Test
@DisplayName( "RAF๋ฅผ ์ด์šฉํ•˜์—ฌ ํŒŒ์ผ์˜ ๋งˆ์ง€๋ง‰ 500 ๋ฐ”์ดํŠธ ์ฝ๊ธฐ" )
void random_access_file_test() throws IOException {
    ClassPathResource resource = new ClassPathResource("gc.log");
    int lastNBytes = 500;
    // ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ํŒŒ์ผ์„ ์—ฐ๋‹ค.
    try( RandomAccessFile raf = new RandomAccessFile(resource.getFile(), "r") ) {
        // ์ „์ฒด ํฌ๊ธฐ
        long totalSize = raf.length();
        System.out.println("ํŒŒ์ผ ์ „์ฒด ํฌ๊ธฐ: " + totalSize);

        long startPos = totalSize - lastNBytes;
        // lastNBytes๊ฐ€ ํŒŒ์ผ์˜ ์ „์ฒด ํฌ๊ธฐ๋ณด๋‹ค ํฌ๋ฉด ์ฒ˜์Œ๋ถ€ํ„ฐ ์ฝ์Œ
        if ( startPos < 0 ) {
            startPos = 0;
        }

        // ํŒŒ์ผ ํฌ์ธํ„ฐ๋ฅผ startPos ์œ„์น˜๋กœ ์ด๋™
        raf.seek( startPos );
        System.out.println("์ปค์„œ ์œ„์น˜ ์ด๋™: " + raf.getFilePointer());

        byte[] buf = new byte[lastNBytes];
        // buf๊ฐ€ ๋ชจ๋‘ ์ฑ„์›Œ์งˆ ๋•Œ๊นŒ์ง€ ์ฝ์Œ์„ ๋ณด์žฅ
        raf.readFully( buf );

        System.out.println("---- ๋งˆ์ง€๋ง‰ " + lastNBytes + " ๋ฐ”์ดํŠธ ๋‚ด์šฉ ----");
        System.out.println( new String(buf) );
        System.out.println("---- ๋ ----");
    }
    catch ( IOException e ) {
        e.printStackTrace();
    }
}
Java

test/resources/gc.log ํŒŒ์ผ์˜ ๋งˆ์ง€๋ง‰ 500byte ๋‚ด์šฉ์„ ์ฝ์–ด ์ถœ๋ ฅํ•˜๋Š” ์ฝ”๋“œ๋‹ค. ์ŠคํŠธ๋ฆผ ๋ฐฉ์‹์€ ํŒŒ์ผ์˜ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋งˆ์ง€๋ง‰๊นŒ์ง€ ์ฝ์–ด์•ผ ํ•˜์ง€๋งŒ RandomAccessFile์€ ๋ฐ”๋กœ ๋งˆ์ง€๋ง‰ 500 byte ์œ„์น˜๋กœ ๋ฐ”๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋‹ค.

์–ด๋–ค ๊ฑธ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„๊นŒ?

๊ฐ๊ฐ์˜ ์ƒํ™ฉ์— ๋”ฐ๋ผ ์–ด๋–ค ํŒŒ์ผ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€์ง€ ํ‘œ๋กœ ์ •๋ฆฌํ•ด๋ดค๋‹ค.

์ถ”์ฒœ ํด๋ž˜์Šค์„ค๋ช…
์ˆœ์ฐจ์ ์ธ ํŒŒ์ผ ์ฝ๊ธฐBufferedInputStream (with FileInputStream)๋ฒ„ํผ๋ง์„ ํ†ตํ•œ ์‹œ์Šคํ…œ ์ฝœ ์ตœ์†Œํ™”๋กœ ๋†’์€ ์„ฑ๋Šฅ ์ œ๊ณต (default 8KB ๋ฒ„ํผ ํ™œ์šฉ)
ํŒŒ์ผ ํฌ๋งท ํ™•์ธBufferedInputStream (mark / reset)ํŒŒ์ผ์˜ ์ฒซ ๋ฐ”์ดํŠธ๋ฅผ ์ฝ์–ด ํŒŒ์ผ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ํ™•์ธ ํ›„ ๋‹ค์‹œ ์ฝ๊ธฐ
๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ ์ž„์˜ ์ ‘๊ทผRandomAccessFile๋ฉ”๋ชจ๋ฆฌ ์†Œ๋ชจ ์—†์ด ๋””์Šคํฌ์˜ ์–ด๋А ์œ„์น˜๋กœ๋“  ์ด๋™ ๊ฐ€๋Šฅ (seek)
๋ฐ์ดํ„ฐ ์ˆ˜์ •RandomAccessFileํŒŒ์ผ ์ค‘๊ฐ„์˜ ํŠน์ • ๋ฐ”์ดํŠธ์—ด์— ๋Œ€ํ•ด์„œ ์ˆ˜์ • ๊ฐ€๋Šฅ (์ŠคํŠธ๋ฆผ์€ ๋ถˆ๊ฐ€)

    ์ŠคํŠธ๋ฆผ์—์„œ ํŒŒ์ผ์„ ์ฝ์€ ํ›„์— ๋‹ค์‹œ ์ด์ „์œผ๋กœ ๋˜๋Œ๋ ค์„œ ์ฝ์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ BufferedInputStream ์ด๋‚˜ ByteArrayInputStream ์‚ฌ์šฉ์„ ๊ฒ€ํ† ํ•ด ๋ณด๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ByteInputStream์˜ ๊ฒฝ์šฐ์—๋Š” ํŒŒ์ผ ๋‚ด์šฉ ์ „์ฒด๋ฅผ ๋กœ๋”ฉํ•˜๋ฉด ํŒŒ์ผ ๋‚ด์šฉ ์ „์ฒด๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐ€๋ฏ€๋กœ ํž™ ์‚ฌ์šฉ๋Ÿ‰์ด ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ž‘์€ ํŒŒ์ผ ์ฒ˜๋ฆฌ์—์„œ๋งŒ ๊ณ ๋ คํ•˜๊ธฐ ๋ฐ”๋ž€๋‹ค.
    ๋˜ํ•œ ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ์ด๋‚˜ ์žฆ์€ ์œ„์น˜ ์ด๋™์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” RandomAccessFile์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹๊ฒ ๋‹ค.
    ์ฐธ๊ณ ๋กœ Java NIO์˜ FileChannel์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋งคํ•‘(MappedByteBuffer)๋“ฑ์„ ํ†ตํ•ด ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ์„ ๋” ํšจ์œจ์ ์œผ๋กœ ๋žœ๋ค ์•ก์„ธ์Šค ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋ถ€๋ถ„์€ ์ถ”ํ›„ ํฌ์ŠคํŒ…์œผ๋กœ ์ •๋ฆฌํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

    ๋งŽ์€ ๋„์›€์ด ๋˜์—ˆ๊ธธ ๋ฐ”๋ผ๋ฉฐ..

    ๋.


    ์ฐธ๊ณ 

    https://www.baeldung.com/java-inputstream-reset-file-read