[Java] I/O Stream

Jeini·2025년 9월 26일
0

☕️  Java

목록 보기
68/70
post-thumbnail

📌 I/O Stream

✅ 데이터 입출력용 스트림, 메서드 체이닝이나 람다랑은 별개


  • Stream = 데이터를 한 줄로 흐르게 만드는 것
  • 입력 스트림(InputStream) = 데이터 읽기용
  • 출력 스트림(OutputStream) = 데이터 쓰기, 데이터 저장용
  • 데이터는 바이트 단위 또는 문자 단위로 흘러감
  • 한 번 읽으면 사라지는 파이프 같은 느낌

💡 직관적으로 생각하면, 수도관(pipe) 같음: 물(데이터)을 흘려보내고, 끝에서 받아 사용.


📌 바이트 기반 스트림과 문자 기반 스트림


종류용도대표 클래스
바이트 스트림모든 파일/데이터 (이미지, 동영상, exe 등)InputStream, OutputStream, FileInputStream, FileOutputStream
문자 스트림텍스트 파일Reader, Writer, FileReader, FileWriter, BufferedReader, BufferedWriter

📌 console 입출력

🔑 정리

방식입력장점단점
System.in.read()한 바이트가장 기본, 단순한 글자씩, 변환 필요
Scanner문자열, 숫자 등사용 편함, 다양한 타입 지원버퍼 문제 주의
BufferedReader문자열빠르고 효율적타입 변환 직접 해야 함

1️⃣ System.out — 콘솔 출력

  • System.out = 콘솔로 출력하는 표준 출력 스트림
  • 대표 메서드: print(), println(), printf()
public class Main {
    public static void main(String[] args) {
        System.out.print("Hello ");      // 줄 바꿈 없음
        System.out.println("World!");    // 줄 바꿈 포함
        System.out.printf("숫자: %d\n", 100); // 서식 지정 출력
    }
}

2️⃣ System.in — 콘솔 입력

  • System.in = 콘솔에서 데이터를 바이트 단위로 읽는 입력 스트림
  • 그대로 쓰면 바이트 단위 → 문자/문자열로 변환 필요
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        System.out.println("문자 하나 입력:");
        int input = System.in.read(); // 한 글자 읽기 (ASCII 코드)
        System.out.println("입력한 문자: " + (char) input);
    }
}

💡 주의: System.in.read()Enter까지 포함해서 버퍼에서 읽기 때문에 여러 글자를 읽으려면 반복 필요.


3️⃣ Scanner 클래스 사용 ⭐️

  • System.in 을 더 쉽게 사용할 수 있게 해주는 도구
  • 문자열, 정수, 실수 등 바로 읽기 가능
  • 장점:
    타입별 입력 가능 (nextInt() , nextDouble() , next() , nextLine())
    입력 버퍼 처리 간편
  • 단점:
    nextInt() + nextLine() 같이 쓰면 버퍼 문제 발생 → 주의 필요
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.print("이름 입력: ");
        String name = sc.nextLine();    // 한 줄 읽기

        System.out.print("나이 입력: ");
        int age = sc.nextInt();         // 정수 읽기

        System.out.println(name + "님의 나이는 " + age + "세입니다.");

        sc.close(); // 스캐너 닫기
    }
}

4️⃣ BufferedReader 사용 (문자 기반)

  • Scanner 보다 빠르고 효율적, 한 줄 단위 입력 가능
  • 특징:
    속도 빠름 (Scanner보다)
    타입 변환 직접 해줘야 함 (Integer.parseInt 등)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("이름 입력: ");
        String name = br.readLine();

        System.out.print("나이 입력: ");
        int age = Integer.parseInt(br.readLine()); // 문자열 → 정수 변환

        System.out.println(name + "님의 나이는 " + age + "세입니다.");
    }
}

📌 File 입출력

  • 파일 읽기 → FileInputStream , FileReader, BufferedReader
  • 파일 쓰기 → FileOutputStream, FileWriter, BufferedWriter
  • ⭐️ 중요:
    스트림 사용 후 반드시 닫아야 함 (close())
    안 닫으면 자원 누수, 파일 잠금 문제 발생

🔑 정리

항목설명
try-catch-finally파일 열기 → 작업 → 오류 처리 → finally에서 자원 해제
close()스트림/리더/라이터 종료. 안 하면 파일 잠김/자원 누수 발생
try-with-resourcesAutoCloseable 구현 객체 자동 close, 코드 간결

항목읽기쓰기특징
바이트 스트림FileInputStreamFileOutputStream모든 파일, 바이트 단위, 이미지/동영상 가능
문자 스트림FileReader, BufferedReaderFileWriter, BufferedWriter텍스트 파일, 한 줄 단위 처리 가능, 빠름

1️⃣ 파일 읽기 (File Input)

1. 바이트 단위 읽기 – FileInputStream

  • 모든 파일 읽기 가능 (텍스트, 이미지, 동영상 등)
  • 한 바이트씩 읽음
import java.io.FileInputStream;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("example.txt")) { // try-with-resources
            int data;
            while ((data = fis.read()) != -1) { // -1 = 파일 끝
                System.out.print((char) data);
            }
        } catch (IOException e) {
            System.out.println("파일 읽기 오류: " + e.getMessage());
        }
    }
}

2 문자 단위 읽기 – BufferedReader

  • 텍스트 파일 전용
  • 한 줄씩 읽기 가능, 속도 빠름
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader("example.txt"))) {
            String line;
            while ((line = br.readLine()) != null) { // 한 줄씩 읽기
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("파일 읽기 오류: " + e.getMessage());
        }
    }
}

2️⃣ 파일 쓰기 (File Output)

1. 바이트 단위 쓰기 – FileOutputStream

  • 모든 파일 쓰기 가능
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        String text = "Hello File I/O!";
        try (FileOutputStream fos = new FileOutputStream("output.txt")) {
            fos.write(text.getBytes()); // 문자열 → 바이트 배열
        } catch (IOException e) {
            System.out.println("파일 쓰기 오류: " + e.getMessage());
        }
    }
}

2. 문자 단위 쓰기 – BufferedWriter

  • 텍스트 파일 전용
  • 한 줄씩 쓰기 가능, 속도 빠름
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {
            bw.write("Hello BufferedWriter!");
            bw.newLine(); // 줄바꿈
            bw.write("두 번째 줄");
        } catch (IOException e) {
            System.out.println("파일 쓰기 오류: " + e.getMessage());
        }
    }
}

⚙️ try-catch-finally

  • try : 파일 열고 읽기 시도
  • catch : 예외 발생 시 처리
  • finally : 무조건 실행 → 자원 해제(닫기)

✏️ 파일 읽기

import java.io.FileReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        FileReader fr = null;

        try {
            fr = new FileReader("example.txt"); // 파일 열기
            int data;
            while ((data = fr.read()) != -1) {
                System.out.print((char) data); // 한 글자씩 출력
            }
        } catch (IOException e) {
            System.out.println("파일 읽기 오류: " + e.getMessage());
        } finally {
            // 자원 해제
            try {
                if (fr != null) fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

✏️ 파일 쓰기

import java.io.FileWriter;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        FileWriter fw = null;

        try {
            fw = new FileWriter("output.txt");
            fw.write("Hello File I/O!\n");
            fw.write("Java 입출력 연습");
        } catch (IOException e) {
            System.out.println("파일 쓰기 오류: " + e.getMessage());
        } finally {
            try {
                if (fw != null) fw.close(); // 자원 해제
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

⚙️ try-with-resources ⭐️

  • Java 7 이후 도입
  • 자동으로 자원 닫기 (close() 자동 호출)
  • 코드 훨씬 간결하고 안전
  • ✅ 장점:
    finally 에서 close() 안 써도 됨
    중첩 try-catch 없이 깔끔하게 작성 가능
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        // BufferedReader는 AutoCloseable을 구현함
        try (BufferedReader br = new BufferedReader(new FileReader("example.txt"))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("파일 읽기 오류: " + e.getMessage());
        }
        // br.close() 자동 호출
    }
}

💡 파일 입출력 개선 - 한국어 이슈

❗️ 한글 같은 멀티바이트 문자 때문에 Java 파일 입출력에서 주의

1️⃣ 문제 원인

  • char: Java에서 2바이트 (UTF-16)
  • FileReader / FileWriter: 기본 문자셋(encoding) 사용
  • 한글/특수문자는 바이트 수가 달라질 수 있음 → 깨짐

예:

  • UTF-8: 한글 1글자 = 3바이트
  • UTF-16: 한글 1글자 = 2바이트
  • FileReader /FileWriter플랫폼 기본 인코딩 사용 → 환경 따라 깨질 수 있음

2️⃣ 해결 방법

1. char 크기 입력 받기

  • char = 2바이트 (Java 내부)
  • 파일 저장/읽기 = 바이트 단위
  • 따라서 한글 한 글자를 읽고 쓸 때는 char 단위로 읽으면 안전
  • byte 단위로 읽으면 인코딩 문제 발생 가능

💡 Tip: 바이트 단위(FileInputStream , FileOutputStream)로 처리할 때는 인코딩 변환 필수

✏️ FileReader + 한 글자씩 읽기

import java.io.FileReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try (FileReader fr = new FileReader("example.txt")) {
            int c;
            while ((c = fr.read()) != -1) {  // 한 글자씩 읽기
                System.out.print((char) c);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • fr.read() → 한 글자(char) 단위 읽기
  • 한글도 Java 내부에서는 char 2바이트로 읽히므로 안전
  • 속도 느림, 큰 파일에는 비효율적

✏️ FileReader + char 배열 버퍼로 읽기

import java.io.FileReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try (FileReader fr = new FileReader("example.txt")) {
            char[] buffer = new char[8]; // 버퍼 크기
            int len;
            while ((len = fr.read(buffer)) != -1) { // 한 번에 버퍼만큼 읽기
                System.out.print(new String(buffer, 0, len)); // char -> 문자열
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • fr.read(buffer)char 배열 단위로 읽기
  • 한 번에 여러 글자 읽어서 속도 빠름
  • 마지막 읽기는 len 만큼만 사용

✏️ BufferedReader + 한 글자씩 읽기

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader("example.txt"))) {
            int c;
            while ((c = br.read()) != -1) {  // 한 글자씩 읽기
                System.out.print((char) c);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 내부적으로 버퍼 사용 → 속도 FileReader 단독보다 빠름
  • 한글/멀티바이트 문자도 char 단위로 안전하게 읽음

🔑 정리

방식단위장점단점
FileReader.read()char 1개간단, 한 글자 처리속도 느림
FileReader.read(char[] buffer)char 배열속도 빠름코드 조금 복잡
BufferedReader.read()char 1개내부 버퍼 사용 → 빠름한 줄 단위 처리가 필요하면 readLine 사용 추천

2. InputStreamReader / OutputStreamWriter + 인코딩 지정

  • ✅ 장점: 인코딩 명시 → 어떤 환경에서도 한글 깨짐 방지
  • BufferedReader + InputStreamReader 조합이 가장 많이 쓰임
import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        // UTF-8로 파일 쓰기
        try (OutputStreamWriter osw = new OutputStreamWriter(
                new FileOutputStream("example.txt"), "UTF-8")) {
            osw.write("안녕하세요 Java 입출력!");
        }

        // UTF-8로 파일 읽기
        try (InputStreamReader isr = new InputStreamReader(
                new FileInputStream("example.txt"), "UTF-8");
             BufferedReader br = new BufferedReader(isr)) {

            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}

📌 Image 입출력

❗️ 텍스트 파일과 달리 이미지는 바이트 단위 처리 또는 이미지 전용 API를 써야 한다.

🔑 정리

방법장점단점용도
바이트 스트림 (FileInputStream / FileOutputStream)모든 파일 가능, 단순 복사픽셀 조작 불가파일 복사, 단순 입출력
ImageIO + BufferedImage픽셀 단위 조작 가능, 형식 변환 가능메모리 사용 ↑, 복잡이미지 편집, 변환, 처리

1️⃣ FileInputStream / FileOutputStream 이용

  • 바이트 단위로 이미지 읽고 쓰기

✅ 특징

  • 모든 파일 종류에 사용 가능 (텍스트, 이미지, 동영상 등)
  • 바이트 단위 → 한 번에 큰 덩어리(buffer) 읽어서 속도 개선 가능
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("input.jpg");
             FileOutputStream fos = new FileOutputStream("output.jpg")) {

            byte[] buffer = new byte[1024]; // 1KB 버퍼
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }

            System.out.println("이미지 복사 완료!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2️⃣ ImageIO 사용 (BufferedImage)

  • javax.imageio.ImageIO 를 사용하면 이미지 파일을 BufferedImage 객체로 읽고 쓰기 가능
  • 픽셀 단위 조작도 가능
  • ImageIO 로 읽은 이미지는 BufferedImage 객체 → 픽셀 정보 (getRGB/setRGB) 접근 가능

✅ 장점

  • 픽셀 단위 조작 가능
  • PNG, JPG, GIF 등 여러 형식 지원
  • ImageIO.write() 로 다른 형식으로 변환 가능 (예: JPG → PNG)
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try {
            // 이미지 읽기
            BufferedImage img = ImageIO.read(new File("input.jpg"));

            // 이미지 정보 출력
            System.out.println("가로: " + img.getWidth());
            System.out.println("세로: " + img.getHeight());

            // 이미지 저장 (다른 이름, 같은 형식)
            ImageIO.write(img, "jpg", new File("output.jpg"));

            System.out.println("이미지 저장 완료!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

📌 보조 Stream

✅ 다른 스트림(InputStream / OutputStream)을 감싸서 기능을 확장한 스트림

  • 바이트 스트림 → 문자 스트림으로 변환하거나, 버퍼링, 데이터 변환, 압축 등을 가능하게 함
  • 속도 개선
  • 사용성 개선

💡 예: InputStreamReader , BufferedReader , PrintWriter

🔑 정리

스트림역할특징
InputStreamReader바이트 → 문자 변환인코딩 지정 가능
OutputStreamWriter문자 → 바이트 변환인코딩 지정 가능
BufferedReader버퍼링, readLine() 제공속도 빠름
BufferedWriter버퍼링, newLine() 제공속도 빠름

1️⃣ InputStreamReader + BufferedReader

  • 바이트 스트림(FileInputStream) → 문자 스트림(InputStreamReader) → 버퍼링(BufferedReader)
  • 이렇게 하면 한 줄씩 문자열 읽기 가능
import java.io.*;

public class Main {
    public static void main(String[] args) {
        try (
            FileInputStream fis = new FileInputStream("example.txt"); // 바이트 스트림
            InputStreamReader isr = new InputStreamReader(fis, "UTF-8"); // 문자 스트림 변환
            BufferedReader br = new BufferedReader(isr) // 버퍼링
        ) {
            String line;
            while ((line = br.readLine()) != null) { // 한 줄 단위로 읽기
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • InputStreamReader : 바이트 → 문자 변환 (인코딩 지정 가능)
  • BufferedReader : 버퍼링 → 속도 향상 + readLine() 제공

2️⃣ OutputStreamWriter + BufferedWriter

  • 문자 → 바이트 변환 + 버퍼링 → 파일에 쓰기
import java.io.*;

public class Main {
    public static void main(String[] args) {
        try (
            FileOutputStream fos = new FileOutputStream("output.txt");
            OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
            BufferedWriter bw = new BufferedWriter(osw)
        ) {
            bw.write("안녕하세요, Java 보조 스트림!");
            bw.newLine();
            bw.write("한 줄씩 쓰기 편함");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • OutputStreamWriter : 문자 → 바이트 변환
  • BufferedWriter : 버퍼링 + newLine() 지원
profile
Fill in my own colorful colors🎨

0개의 댓글