본문 바로가기
Programming

JAVA 파일 입출력 (File I/O)

by 나무수피아는 지식의 가지를 뻗어가는 공간입니다. 2025. 11. 21.
반응형

📘 파일 입출력 (File I/O)

자바에서는 텍스트 파일을 읽고 쓰거나, 객체를 파일로 저장/복원할 수 있습니다. 이번 강의에서는 File 클래스부터, BufferedReader/Writer, 객체 직렬화(Serializable)까지 파일 입출력의 핵심을 익힙니다. 파일 입출력은 자바 프로그래밍에서 매우 중요한 영역으로, 데이터 저장, 로그 기록, 설정 파일 관리 등 다양한 분야에서 폭넓게 활용됩니다. 특히 텍스트 기반 데이터뿐 아니라 바이너리 데이터도 다룰 수 있어, 실무에서 반드시 익혀야 할 기술입니다.


📌 목차

  1. File 클래스 소개 및 주요 메서드
  2. BufferedReader와 BufferedWriter 사용법과 성능 이점
  3. 객체 직렬화와 역직렬화의 이해와 활용
  4. 파일 입출력 시 예외 처리 및 자원 관리 방법

🔹 1. File 클래스 사용

자바에서 파일과 디렉터리를 다루는 가장 기본적인 클래스가 File입니다. 이 클래스는 파일의 존재 여부 확인, 경로 정보 조회, 파일 삭제, 이름 변경 등의 기능을 제공합니다. 실제 파일 내용을 읽거나 쓰지는 않지만, 파일의 메타정보를 조작하는 데 매우 유용합니다.

import java.io.File;

public class FileExample {
    public static void main(String[] args) {
        File file = new File("test.txt");

        if (file.exists()) {
            System.out.println("파일 이름: " + file.getName());
            System.out.println("경로: " + file.getAbsolutePath());
            System.out.println("파일 크기 (byte): " + file.length());
            System.out.println("읽기 가능: " + file.canRead());
            System.out.println("쓰기 가능: " + file.canWrite());
            System.out.println("숨김 파일 여부: " + file.isHidden());
        } else {
            System.out.println("파일이 존재하지 않습니다.");
        }
    }
}

출력 예:
파일 이름: test.txt
경로: C:\workspace\test.txt
파일 크기 (byte): 1024
읽기 가능: true
쓰기 가능: true
숨김 파일 여부: false


🔹 2. BufferedReader / BufferedWriter 사용법

텍스트 파일을 효율적으로 읽고 쓰기 위한 클래스로, BufferedReaderBufferedWriter는 내부 버퍼를 사용해 입출력 성능을 향상합니다. 한 줄씩 읽고 쓸 수 있어 로그 파일 처리, 텍스트 데이터 조작 등에 적합합니다.

import java.io.*;

public class TextIOExample {
    public static void main(String[] args) {
        try {
            // 파일 쓰기
            BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"));
            writer.write("Hello, File I/O!");
            writer.newLine();
            writer.write("BufferedReader와 BufferedWriter는 효율적인 텍스트 입출력에 필수입니다.");
            writer.newLine();
            writer.close();

            // 파일 읽기
            BufferedReader reader = new BufferedReader(new FileReader("output.txt"));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            reader.close();
        } catch (IOException e) {
            System.out.println("입출력 오류: " + e.getMessage());
        }
    }
}

출력:
Hello, File I/O!
BufferedReader와 BufferedWriter는 효율적인 텍스트 입출력에 필수입니다.

이처럼 버퍼링을 활용하면 파일 I/O 속도를 크게 개선할 수 있으며, 특히 대용량 파일 처리 시 성능 차이가 큽니다. 또한 try-with-resources 문을 사용하면 자원 자동 해제가 가능해 더욱 안전한 코드 작성이 가능합니다.


🔹 3. 객체 직렬화 (Serializable)와 역직렬화

객체 직렬화란 메모리에 있는 객체를 바이트 스트림 형태로 변환하여 파일에 저장하거나 네트워크를 통해 전송하는 과정입니다. 반대로 역직렬화는 저장된 바이트 스트림을 다시 객체로 복원하는 것을 말합니다. 자바에서는 Serializable 인터페이스를 구현함으로써 쉽게 객체 직렬화를 지원합니다.

import java.io.*;

class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "이름: " + name + ", 나이: " + age;
    }
}

public class SerializationExample {
    public static void main(String[] args) {
        Person person = new Person("Tom", 30);

        try {
            // 객체 저장 (직렬화)
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"));
            oos.writeObject(person);
            oos.close();

            // 객체 복원 (역직렬화)
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"));
            Person restored = (Person) ois.readObject();
            ois.close();

            System.out.println(restored);
        } catch (IOException | ClassNotFoundException e) {
            System.out.println("오류 발생: " + e.getMessage());
        }
    }
}

출력:
이름: Tom, 나이: 30

객체 직렬화는 게임 저장, 세션 관리, 분산 처리 시스템 등에서 매우 중요합니다. 단, transient 키워드를 사용하면 특정 필드를 직렬화 대상에서 제외할 수 있으며, serialVersionUID를 명시하여 버전 관리를 할 수 있습니다. 또한 상속 구조나 복잡한 참조 관계를 가진 객체도 직렬화를 통해 쉽게 저장/복원할 수 있습니다.


🔹 4. 파일 입출력 시 예외 처리 및 자원 관리

파일 입출력은 외부 리소스를 다루기 때문에 예외 처리가 반드시 필요합니다. 또한 입출력 스트림을 다 사용한 후에는 반드시 닫아야 하며, 그렇지 않으면 메모리 누수나 파일 잠금 문제가 발생할 수 있습니다.

import java.io.*;

public class SafeFileIO {
    public static void main(String[] args) {
        // try-with-resources 구문으로 자원 자동 해제
        try (BufferedReader reader = new BufferedReader(new FileReader("safe.txt"));
             BufferedWriter writer = new BufferedWriter(new FileWriter("safe_out.txt"))) {

            String line;
            while ((line = reader.readLine()) != null) {
                // 간단히 읽은 내용을 그대로 출력 파일에 씀
                writer.write(line);
                writer.newLine();
            }
        } catch (IOException e) {
            System.out.println("파일 입출력 중 오류 발생: " + e.getMessage());
        }
    }
}

자바 7부터 도입된 try-with-resources 구문은 입출력 스트림, 데이터베이스 연결 등 자동으로 닫혀야 하는 리소스들을 편리하게 관리해 줍니다. 이 방법을 사용하면 finally 블록에서 직접 닫지 않아도 돼 코드가 간결해지고 안전성이 향상됩니다.


🔹 5. 추가 팁: 파일 경로와 인코딩 문제 다루기

파일 입출력에서 종종 문제 되는 부분 중 하나는 파일 경로 처리문자 인코딩입니다. 운영체제별 경로 구분자가 다르므로 File.separator를 사용하는 것이 안전합니다. 또한 텍스트 파일 읽고 쓸 때 기본 인코딩을 명시하지 않으면 환경에 따라 한글 깨짐 현상이 발생할 수 있습니다.

import java.io.*;

public class EncodingExample {
    public static void main(String[] args) {
        try (BufferedWriter writer = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream("utf8.txt"), "UTF-8"))) {
            writer.write("안녕하세요, UTF-8 인코딩 예제입니다.");
        } catch (IOException e) {
            System.out.println("쓰기 오류: " + e.getMessage());
        }

        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream("utf8.txt"), "UTF-8"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("읽기 오류: " + e.getMessage());
        }
    }
}

이처럼 InputStreamReaderOutputStreamWriter를 사용하면 명시적으로 인코딩을 지정할 수 있어 한글 및 다국어 문자 처리 시 문제를 예방할 수 있습니다.


🔹 6. 마무리 및 정리

이번 강의에서는 자바 파일 입출력의 핵심 개념과 실습 예제를 통해 File 클래스, BufferedReader/Writer, 객체 직렬화, 그리고 안전한 예외 처리와 자원 관리 방법까지 폭넓게 살펴보았습니다. 실제 프로젝트에서 파일 I/O는 데이터 저장, 설정, 통신, 로그 기록 등 다양한 용도로 활용되므로 이번 내용을 충분히 이해하고 연습하는 것이 중요합니다.

다음과 같은 점들을 기억하세요:

  • File 클래스는 파일과 디렉토리의 메타 정보를 제공한다.
  • BufferedReader/Writer를 사용하면 텍스트 입출력을 효율적으로 처리할 수 있다.
  • Serializable 인터페이스를 구현하면 객체를 파일로 쉽게 저장하고 복원할 수 있다.
  • try-with-resources를 활용해 자원을 안전하게 관리하자.
  • 파일 경로나 인코딩 문제를 미리 처리하면 입출력 오류를 줄일 수 있다.

지속적으로 다양한 파일 입출력 관련 API와 기법들을 실습하며, 본인의 프로젝트에 맞는 최적의 방법을 찾아보시길 권장합니다.

반응형

'Programming' 카테고리의 다른 글

JAVA 클래스 고급  (40) 2025.11.23
JAVA 날짜와 시간 처리  (35) 2025.11.22
JAVA 문자열 처리  (58) 2025.11.20
JAVA 컬렉션 프레임워크  (59) 2025.11.19
JAVA 예외 처리  (59) 2025.11.18