본문 바로가기
  • 코딩, 허쌤이 떠먹여 줄게
BackEnd/Java

11장. 입출력(IO) & 파일 처리

by 허쌤 2026. 1. 2.

11장. 입출력(IO) & 파일 처리

입출력이란?

입출력(I/O)의 개념

입출력(Input/Output)은 프로그램과 외부 환경(파일, 네트워크, 키보드, 모니터 등) 간의 데이터 교환을 의미합니다.

입출력의 종류

  1. 표준 입출력: 콘솔(키보드, 모니터)을 통한 입출력
  2. 파일 입출력: 파일을 통한 데이터 저장 및 읽기
  3. 네트워크 입출력: 네트워크를 통한 데이터 교환

스트림 개념

스트림(Stream)이란?

스트림은 데이터가 흐르는 통로입니다. Java에서는 모든 입출력이 스트림을 통해 이루어집니다.

스트림의 특징

  1. 단방향: 입력 스트림과 출력 스트림이 분리됨
  2. 순차적: 데이터가 순서대로 처리됨
  3. 연속적: 데이터가 연속적으로 흐름

스트림의 종류

1. 바이트 스트림 (Byte Stream)

  • 단위: 바이트(byte) 단위로 데이터 처리
  • 용도: 이미지, 동영상, 실행 파일 등 바이너리 데이터
  • 클래스: InputStream, OutputStream 계열

2. 문자 스트림 (Character Stream)

  • 단위: 문자(char) 단위로 데이터 처리
  • 용도: 텍스트 파일 처리
  • 클래스: Reader, Writer 계열

스트림 계층 구조

InputStream (추상 클래스)
├── FileInputStream
├── BufferedInputStream
└── ObjectInputStream

OutputStream (추상 클래스)
├── FileOutputStream
├── BufferedOutputStream
└── ObjectOutputStream

Reader (추상 클래스)
├── FileReader
├── BufferedReader
└── InputStreamReader

Writer (추상 클래스)
├── FileWriter
├── BufferedWriter
└── OutputStreamWriter

파일 입출력

파일이란?

파일(File)은 데이터를 영구적으로 저장하는 저장소입니다. 프로그램이 종료되어도 데이터가 유지됩니다.

파일 경로

절대 경로

  • 전체 경로를 지정
  • 예: C:\Users\user\Documents\file.txt (Windows)
  • 예: /home/user/documents/file.txt (Linux/Mac)

상대 경로

  • 현재 위치를 기준으로 한 경로
  • 예: data/file.txt
  • 예: ../parent/file.txt

File 클래스

파일과 디렉토리를 다루는 클래스입니다.

import java.io.File;

File file = new File("data.txt");
System.out.println("파일 존재: " + file.exists());
System.out.println("파일 크기: " + file.length() + " bytes");
System.out.println("절대 경로: " + file.getAbsolutePath());

바이트 스트림

바이트 스트림이란?

바이트 단위로 데이터를 읽고 쓰는 스트림입니다. 바이너리 데이터 처리에 사용됩니다.

FileInputStream

파일에서 바이트 단위로 데이터를 읽는 클래스입니다.

기본 사용법

import java.io.FileInputStream;
import java.io.IOException;

FileInputStream fis = null;
try {
    fis = new FileInputStream("data.txt");
    int data;
    while ((data = fis.read()) != -1) {
        System.out.print((char) data);
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fis != null) {
        try {
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

try-with-resources 사용 (권장)

try (FileInputStream fis = new FileInputStream("data.txt")) {
    int data;
    while ((data = fis.read()) != -1) {
        System.out.print((char) data);
    }
} catch (IOException e) {
    e.printStackTrace();
}
// 자동으로 close() 호출됨

FileOutputStream

파일에 바이트 단위로 데이터를 쓰는 클래스입니다.

기본 사용법

import java.io.FileOutputStream;
import java.io.IOException;

try (FileOutputStream fos = new FileOutputStream("output.txt")) {
    String text = "Hello, World!";
    fos.write(text.getBytes());
} catch (IOException e) {
    e.printStackTrace();
}

파일 추가 모드

// 파일에 추가 (append 모드)
try (FileOutputStream fos = new FileOutputStream("output.txt", true)) {
    String text = "\n추가 텍스트";
    fos.write(text.getBytes());
} catch (IOException e) {
    e.printStackTrace();
}

BufferedInputStream / BufferedOutputStream

버퍼를 사용하여 입출력 성능을 향상시키는 클래스입니다.

import java.io.*;

// 버퍼를 사용한 파일 읽기
try (BufferedInputStream bis = new BufferedInputStream(
        new FileInputStream("data.txt"))) {
    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = bis.read(buffer)) != -1) {
        System.out.write(buffer, 0, bytesRead);
    }
} catch (IOException e) {
    e.printStackTrace();
}

// 버퍼를 사용한 파일 쓰기
try (BufferedOutputStream bos = new BufferedOutputStream(
        new FileOutputStream("output.txt"))) {
    String text = "Hello, World!";
    bos.write(text.getBytes());
} catch (IOException e) {
    e.printStackTrace();
}

문자 스트림

문자 스트림이란?

문자 단위로 데이터를 읽고 쓰는 스트림입니다. 텍스트 파일 처리에 최적화되어 있습니다.

FileReader

파일에서 문자 단위로 데이터를 읽는 클래스입니다.

기본 사용법

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

try (FileReader fr = new FileReader("data.txt")) {
    int data;
    while ((data = fr.read()) != -1) {
        System.out.print((char) data);
    }
} catch (IOException e) {
    e.printStackTrace();
}

FileWriter

파일에 문자 단위로 데이터를 쓰는 클래스입니다.

기본 사용법

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

try (FileWriter fw = new FileWriter("output.txt")) {
    fw.write("Hello, World!");
    fw.write("\n안녕하세요!");
} catch (IOException e) {
    e.printStackTrace();
}

파일 추가 모드

// 파일에 추가 (append 모드)
try (FileWriter fw = new FileWriter("output.txt", true)) {
    fw.write("\n추가 텍스트");
} catch (IOException e) {
    e.printStackTrace();
}

BufferedReader / BufferedWriter

버퍼를 사용하여 문자 스트림의 성능을 향상시키는 클래스입니다.

BufferedReader

import java.io.*;

try (BufferedReader br = new BufferedReader(
        new FileReader("data.txt"))) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
}

BufferedWriter

import java.io.*;

try (BufferedWriter bw = new BufferedWriter(
        new FileWriter("output.txt"))) {
    bw.write("첫 번째 줄");
    bw.newLine();  // 줄바꿈
    bw.write("두 번째 줄");
} catch (IOException e) {
    e.printStackTrace();
}

간단한 파일 저장·읽기 예제

예제 1: 텍스트 파일 쓰기

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

public class FileWriteExample {
    public static void main(String[] args) {
        try (FileWriter fw = new FileWriter("data.txt")) {
            fw.write("안녕하세요!\n");
            fw.write("Java 파일 입출력 예제입니다.\n");
            fw.write("12345\n");
            System.out.println("파일 쓰기 완료");
        } catch (IOException e) {
            System.out.println("파일 쓰기 오류: " + e.getMessage());
        }
    }
}

예제 2: 텍스트 파일 읽기

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

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

예제 3: 파일 복사

import java.io.*;

public class FileCopyExample {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(
                new FileReader("source.txt"));
             BufferedWriter bw = new BufferedWriter(
                new FileWriter("destination.txt"))) {

            String line;
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.newLine();
            }
            System.out.println("파일 복사 완료");
        } catch (IOException e) {
            System.out.println("파일 복사 오류: " + e.getMessage());
        }
    }
}

예제 4: 파일 정보 확인

import java.io.File;

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

        if (file.exists()) {
            System.out.println("파일명: " + file.getName());
            System.out.println("절대 경로: " + file.getAbsolutePath());
            System.out.println("파일 크기: " + file.length() + " bytes");
            System.out.println("읽기 가능: " + file.canRead());
            System.out.println("쓰기 가능: " + file.canWrite());
            System.out.println("파일인가: " + file.isFile());
            System.out.println("디렉토리인가: " + file.isDirectory());
        } else {
            System.out.println("파일이 존재하지 않습니다.");
        }
    }
}

바이트 스트림 vs 문자 스트림

구분 바이트 스트림 문자 스트림
단위 바이트 (byte) 문자 (char)
클래스 InputStream/OutputStream Reader/Writer
용도 바이너리 데이터 텍스트 데이터
예시 이미지, 동영상, 실행 파일 텍스트 파일
인코딩 바이트 그대로 처리 문자 인코딩 처리

선택 가이드

  • 텍스트 파일: FileReader, FileWriter, BufferedReader, BufferedWriter
  • 바이너리 파일: FileInputStream, FileOutputStream, BufferedInputStream, BufferedOutputStream

파일 처리 주의사항

1. 리소스 관리

스트림은 반드시 close()를 호출하거나 try-with-resources를 사용해야 합니다.

// 나쁜 예: 리소스 누수
FileReader fr = new FileReader("data.txt");
// close()를 호출하지 않음

// 좋은 예: try-with-resources
try (FileReader fr = new FileReader("data.txt")) {
    // 파일 읽기
}  // 자동으로 close() 호출

2. 예외 처리

파일 입출력은 IOException이 발생할 수 있으므로 반드시 예외 처리가 필요합니다.

try {
    FileReader fr = new FileReader("data.txt");
    // 파일 읽기
} catch (IOException e) {
    System.out.println("파일 읽기 오류: " + e.getMessage());
}

3. 파일 존재 확인

파일을 읽기 전에 존재하는지 확인하는 것이 좋습니다.

File file = new File("data.txt");
if (file.exists() && file.isFile()) {
    // 파일 읽기
} else {
    System.out.println("파일이 존재하지 않습니다.");
}

4. 경로 구분자

운영체제마다 경로 구분자가 다릅니다.

// Windows: \
// Linux/Mac: /

// 플랫폼 독립적인 방법
String path = "data" + File.separator + "file.txt";
// 또는
String path = "data/file.txt";  // 대부분의 경우 작동

실습 예제

예제 1: 학생 정보 파일 저장 및 읽기

import java.io.*;
import java.util.ArrayList;

public class StudentFileManager {
    public static void saveStudents(ArrayList<String> students, String filename) {
        try (BufferedWriter bw = new BufferedWriter(
                new FileWriter(filename))) {
            for (String student : students) {
                bw.write(student);
                bw.newLine();
            }
            System.out.println("파일 저장 완료");
        } catch (IOException e) {
            System.out.println("파일 저장 오류: " + e.getMessage());
        }
    }

    public static ArrayList<String> loadStudents(String filename) {
        ArrayList<String> students = new ArrayList<>();
        try (BufferedReader br = new BufferedReader(
                new FileReader(filename))) {
            String line;
            while ((line = br.readLine()) != null) {
                students.add(line);
            }
        } catch (IOException e) {
            System.out.println("파일 읽기 오류: " + e.getMessage());
        }
        return students;
    }

    public static void main(String[] args) {
        ArrayList<String> students = new ArrayList<>();
        students.add("홍길동,20,컴퓨터공학");
        students.add("김철수,21,전자공학");
        students.add("이영희,20,컴퓨터공학");

        saveStudents(students, "students.txt");

        ArrayList<String> loaded = loadStudents("students.txt");
        for (String student : loaded) {
            System.out.println(student);
        }
    }
}

예제 2: 로그 파일 작성

import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Logger {
    private static final String LOG_FILE = "app.log";

    public static void log(String message) {
        try (BufferedWriter bw = new BufferedWriter(
                new FileWriter(LOG_FILE, true))) {
            String timestamp = LocalDateTime.now()
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            bw.write("[" + timestamp + "] " + message);
            bw.newLine();
        } catch (IOException e) {
            System.err.println("로그 기록 오류: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        log("프로그램 시작");
        log("사용자 로그인");
        log("데이터 처리 완료");
        log("프로그램 종료");
    }
}

연습 문제

  1. 텍스트 파일 쓰기

    • 여러 줄의 텍스트를 파일에 저장하는 프로그램을 작성하세요.
  2. 텍스트 파일 읽기

    • 파일의 모든 내용을 읽어서 출력하는 프로그램을 작성하세요.
  3. 파일 복사

    • 한 파일의 내용을 다른 파일로 복사하는 프로그램을 작성하세요.
  4. 파일 정보 확인

    • 파일의 존재 여부, 크기, 수정 날짜 등을 확인하는 프로그램을 작성하세요.
  5. 학생 정보 관리

    • 학생 정보를 파일에 저장하고 읽는 프로그램을 작성하세요.
  6. 로그 파일

    • 프로그램 실행 로그를 파일에 기록하는 프로그램을 작성하세요.

다음 장 예고

다음 장에서는 Java의 고급 기능들을 학습하여 더욱 효율적인 프로그램을 작성하는 방법을 배웁니다.

'BackEnd > Java' 카테고리의 다른 글

13장. 스레드 & 네트워크(기초)  (0) 2026.01.03
12장. 메모리 구조 & JVM 이해  (0) 2026.01.03
10장. 예외 처리  (0) 2026.01.02
9장. 컬렉션 프레임워크  (0) 2026.01.02
# 8장. 객체지향 핵심 개념  (0) 2026.01.01