CodeGym /행동 /JAVA 25 SELF /파일 및 디렉터리 존재 여부 확인

파일 및 디렉터리 존재 여부 확인

JAVA 25 SELF
레벨 38 , 레슨 1
사용 가능

1. 파일과 디렉터리 존재 여부를 확인하는 방법

파일 작업은 때때로 지뢰밭을 걷는 것과 같습니다: 다음 바이트 뒤에 무엇이 기다리는지 결코 장담할 수 없죠. 좋은 소식: Java는 우리에게 “금속 탐지기”를 제공합니다 — 파일과 폴더의 존재 여부를 확인하는 메서드들입니다.

클래스 File: exists(), isFile(), isDirectory()로 확인하기

가장 고전적인 방법 — java.io.File 클래스를 사용하는 것입니다:

File file = new File("example.txt");
if (file.exists()) {
    System.out.println("파일이 존재합니다!");
} else {
    System.out.println("파일을 찾을 수 없습니다.");
}

메서드 exists()는 해당 이름의 파일 또는 폴더가 존재하면 true를 반환합니다. 하지만 이것만으로 끝이 아닙니다! 무엇이 존재하는지 — 파일인지 디렉터리인지 — 알아야 할 때가 있습니다.

if (file.isFile()) {
    System.out.println("파일입니다.");
} else if (file.isDirectory()) {
    System.out.println("폴더입니다.");
} else {
    System.out.println("아무것도 발견되지 않았습니다.");
}

Path와 Files: 현대적인 접근

현대적인 프로그램에서는 더 새롭고 강력한 API인 java.nio.file을 사용하는 것이 좋습니다. 여기서는 존재 여부 확인에 정적 메서드 Files.exists()를 사용합니다:

import java.nio.file.*;

Path path = Paths.get("example.txt");
if (Files.exists(path)) {
    System.out.println("NIO로 파일을 찾았습니다!");
}

객체의 유형을 확인하려면 다음을 사용하세요:

if (Files.isRegularFile(path)) {
    System.out.println("일반 파일입니다!");
}
if (Files.isDirectory(path)) {
    System.out.println("디렉터리입니다!");
}

팁: 새 프로젝트에서는 NIO(Path, Files)를 바로 사용하는 것이 좋습니다. 더 현대적이고 기능이 많으며 try-with-resources와도 잘 맞기 때문입니다.

표: 접근 방식 비교

방법 존재 여부 확인 유형 확인(파일/폴더) 현대성
File.exists()
예 (isFile(), isDirectory()) 구식
Files.exists(Path)
예 (isRegularFile(), isDirectory()) 권장

2. TOCTOU 문제: 존재 검사만으로는 충분하지 않은 이유

문제의 핵심은?

예를 들어, “파일이 존재한다!”를 확인하자마자 읽으려고 했다고 합시다. 하지만 프로세서의 관점에서 보면 이 두 동작 사이에도 무한대에 가까운 시간이 흐를 수 있습니다. 그 사이에 파일이 삭제되거나, 이동되거나, 다른 프로세스에 의해 대체되거나, 접근 권한이 변경될 수 있습니다.

마치 냉장고를 열어 케이크가 있는 것을 확인하고 문을 닫았다가, 다시 열었더니 케이크가 이미 사라진 것과 같습니다. 프로그래밍에서도 이런 “식구들”이 있습니다: 다른 프로세스, 사용자, 백신, 그리고 파일 시스템 자체입니다.

왜 중요할까요?

결과적으로, 파일이 존재한다고 확인했더라도 열려고 시도하는 순간 여전히 예외가 발생할 수 있습니다 — 예를 들어 FileNotFoundException이나 AccessDeniedException.

따라서 존재 여부 확인은 보장이 아니라 추가적인 안전 장치일 뿐입니다. 항상 예외에 대비하고 처리하세요!

3. 실습: 읽기 전에 파일 존재 여부 확인

파일이 존재하면 내용을 출력하고, 없으면 사용자에게 알려 주는 함수를 추가해 봅시다. 오래된 API와 새로운 API 두 가지 버전을 보여 드립니다.

버전 1: File 사용

import java.io.*;

public class FileExistenceCheck {
    public static void main(String[] args) {
        File file = new File("notes.txt");
        if (file.exists() && file.isFile()) {
            try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                System.out.println("파일을 읽는 중 오류: " + e.getMessage());
            }
        } else {
            System.out.println("파일 'notes.txt'를 찾을 수 없습니다.");
        }
    }
}

버전 2: PathFiles 사용

import java.nio.file.*;
import java.io.IOException;

public class PathExistenceCheck {
    public static void main(String[] args) {
        Path path = Paths.get("notes.txt");
        if (Files.exists(path) && Files.isRegularFile(path)) {
            try {
                Files.lines(path).forEach(System.out::println);
            } catch (IOException e) {
                System.out.println("파일을 읽는 중 오류: " + e.getMessage());
            }
        } else {
            System.out.println("파일 'notes.txt'를 찾을 수 없습니다.");
        }
    }
}

검사 후에도 — 예외를 잡으세요!

두 예제 모두, 사전 확인을 했음에도 trycatch 블록을 사용하는데, 이는 파일이 언제든 사라지거나 접근 불가능해질 수 있기 때문입니다. 이것이 파일 작업의 황금률입니다!

4. 디렉터리 존재 여부 확인

마찬가지로 폴더의 존재 여부를 확인하고, 없으면 생성할 수 있습니다:

import java.nio.file.*;

public class DirectoryCheck {
    public static void main(String[] args) {
        Path dir = Paths.get("data");
        if (Files.exists(dir) && Files.isDirectory(dir)) {
            System.out.println("폴더 'data'를 찾았습니다.");
        } else {
            System.out.println("폴더 'data'를 찾지 못했습니다. 생성합니다...");
            try {
                Files.createDirectory(dir);
                System.out.println("폴더가 생성되었습니다!");
            } catch (IOException e) {
                System.out.println("폴더 생성 중 오류: " + e.getMessage());
            }
        }
    }
}

참고:
메서드 Files.createDirectory()는 폴더가 이미 있으면 예외를 던집니다. 폴더 체인을 만들고 싶다면(예: "data/2025/09"), 일부 폴더가 이미 존재해도 불평하지 않는 Files.createDirectories()를 사용하세요.

5. 알아둘 점: 상대 경로와 절대 경로

상대 경로

"notes.txt"라고 작성하면 프로그램은 “현재 작업 디렉터리”에서 파일을 찾습니다. 위치는 애플리케이션을 어떻게, 어디서 실행하느냐(IDE, 터미널, JAR 더블 클릭 등)에 따라 달라집니다.

절대 경로

어디에서 찾을지 확실히 하려면 절대 경로를 사용하거나, 동적으로 경로를 구성하는 것이 좋습니다:

String userHome = System.getProperty("user.home");
Path filePath = Paths.get(userHome, "myapp", "notes.txt");

객체 유형 확인

가끔 “파일”이 의외로 디렉터리일 수 있습니다. 그러므로 존재 여부뿐만 아니라 유형도 함께 확인하세요:

if (Files.isRegularFile(path)) {
    // 이건 확실히 파일입니다!
}
if (Files.isDirectory(path)) {
    // 이건 폴더입니다!
}

6. TOCTOU 문제를 실제로 시연

파일이 확인 후 열기 전에 사라지는 상황을 시뮬레이션해 봅시다. 코드를 실행한 뒤, 확인과 읽기 사이에서 파일을 수동으로 삭제하세요:

import java.io.*;
import java.nio.file.*;

public class TOCTOUExample {
    public static void main(String[] args) {
        Path path = Paths.get("notes.txt");
        if (Files.exists(path)) {
            System.out.println("파일을 찾았습니다. 이제 읽어 보겠습니다...");
            // 이 지점에서 파일 탐색기로 "notes.txt" 파일을 직접 삭제하세요!
            try {
                Files.lines(path).forEach(System.out::println);
            } catch (IOException e) {
                System.out.println("앗! 파일이 사라졌습니다: " + e.getMessage());
            }
        } else {
            System.out.println("파일을 찾을 수 없습니다.");
        }
    }
}

결과:
확인과 읽기 사이에 파일 삭제에 성공하면 예외가 발생합니다. 이는 아무리 조심스러운 확인이라도 예기치 못한 변경으로부터 완전히 보호해 주지 못한다는 점을 잘 보여 줍니다.

7. 파일과 폴더 존재 여부 확인에서 흔한 실수

오류 №1: try-catch 없이 존재 확인만 믿는다. “파일이 있네, 그러면 그냥 읽으면 되겠지”라고 초보자는 생각합니다. 하지만 파일은 사라지거나 접근 불가능해질 수 있고, 프로그램은 ‘죽을’ 수 있습니다.

오류 №2: 존재만 확인하고 유형은 확인하지 않는다. exists()만 확인하고 파일인지 폴더인지 구분하지 않으면, 폴더를 파일처럼 열려고 하다가 오류가 발생합니다.

오류 №3: 작업 디렉터리를 이해하지 못한 채 상대 경로를 사용한다. 프로그램이 파일을 ‘엉뚱한 곳’에서 찾고, 사용자는 왜 아무것도 동작하지 않는지 이해하지 못합니다.

오류 №4: 접근 권한을 고려하지 않는다. 파일이나 폴더는 존재하지만 읽기/쓰기 권한이 없을 수 있습니다. 이런 문제는 파일을 열려고 할 때만 드러나니 — 항상 trycatch를 사용하세요.

오류 №5: OS마다 다른 파일명 대소문자 민감도를 간과한다. Windows는 파일명이 대소문자를 구분하지 않지만, Linux는 구분합니다. 프로그램이 "notes.txt"를 찾도록 되어 있으면 "Notes.txt"는 찾지 못할 수 있습니다.

1
과제
JAVA 25 SELF, 레벨 38, 레슨 1
잠금
지역 정찰: "data" 은닉처 찾기 🕵️‍♂️
지역 정찰: "data" 은닉처 찾기 🕵️‍♂️
1
과제
JAVA 25 SELF, 레벨 38, 레슨 1
잠금
소중한 자산을 위한 피난처 만들기: 백업 🔐
소중한 자산을 위한 피난처 만들기: 백업 🔐
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION