CodeGym /행동 /JAVA 25 SELF /파일과 폴더의 복사와 이동

파일과 폴더의 복사와 이동

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

1. 파일 복사

메서드 Files.copy: 기본 문법

Java에서는 java.nio.file 패키지의 정적 메서드 Files.copy로 파일과 폴더를 복사합니다. 이미 한 번 만나봤지만, 이제 더 자세히 살펴보겠습니다. Files.copy의 기본 문법은 다음과 같습니다:

Files.copy(Path source, Path target, CopyOption... options)
  • source — 원본 파일 또는 폴더의 경로.
  • target — 복사 대상 경로.
  • options — 추가 옵션(예: 덮어쓰기를 허용).

가장 간단한 예

현재 디렉터리의 "input.txt" 파일을 "backup" 폴더로 "input_backup.txt"라는 이름으로 복사해 보겠습니다:

import java.nio.file.*;

public class CopyExample {
    public static void main(String[] args) throws Exception {
        Path source = Path.of("input.txt");
        Path target = Path.of("backup/input_backup.txt");

        Files.copy(source, target);
        System.out.println("파일이 복사되었습니다!");
    }
}

중요한 포인트:

  • 대상 파일이 이미 존재하면 FileAlreadyExistsException이 발생합니다.
  • "backup" 폴더가 존재하지 않으면 메서드는 오류를 던집니다 — 폴더를 미리 만들어 두어야 합니다!

덮어쓰면서 복사하기

파일 덮어쓰기를 허용하려면 옵션 StandardCopyOption.REPLACE_EXISTING을 사용하세요:

Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);

표: 주요 복사 옵션

옵션 설명
StandardCopyOption.REPLACE_EXISTING
대상 파일이 이미 있으면 덮어씀
StandardCopyOption.COPY_ATTRIBUTES
속성 복사(생성 날짜 등)
StandardCopyOption.ATOMIC_MOVE
원자적 이동(오직 move에서만 사용)

파일을 다른 폴더로 복사

복사하기 전에 대상 폴더가 존재하는지 확인하세요:

Path targetDir = Path.of("backup");
if (!Files.exists(targetDir)) {
    Files.createDirectory(targetDir);
}
Files.copy(source, targetDir.resolve("input_backup.txt"), StandardCopyOption.REPLACE_EXISTING);

디렉터리 복사: 함정

메서드 Files.copy는 폴더를 “빈 껍데기”로만 복사합니다 — 내용(파일과 하위 폴더)은 복사되지 않습니다! 파일이 들어 있는 폴더를 복사하려고 하면 빈 디렉터리만 생깁니다. 내용까지 포함해 전체 디렉터리를 복사하려면 재귀적으로 순회하며 각 파일을 직접 복사해야 합니다(이는 다음 강의에서 다시 다룹니다).

예시: 한 폴더에서 다른 폴더로 파일 복사

Path source = Path.of("data/report.txt");
Path target = Path.of("backup/report.txt");

Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);

복사 시 오류 처리

복사는 여러 이유로 실패할 수 있습니다: 권한 부족, 파일 사용 중, 공간 부족, 대상 파일 존재 등. 항상 try-catch를 사용하는 것이 좋습니다:

try {
    Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
    System.out.println("복사가 성공했습니다!");
} catch (FileAlreadyExistsException e) {
    System.out.println("파일이 이미 존재합니다: " + target);
} catch (IOException e) {
    System.out.println("입출력 오류: " + e.getMessage());
}

2. 파일과 폴더 이동

메서드 Files.move: 문법

파일과 폴더 이동은 다음 메서드로 수행합니다:

Files.move(Path source, Path target, CopyOption... options)

여기서 source — 이동할 원본 경로, target — 파일이나 폴더를 놓을 대상 경로, options — 추가 설정(예: 기존 파일 교체)입니다.

참고로, 이동은 파일을 “옮기는” 것뿐 아니라 이름만 바뀌는 경우에는 이름 변경 방법이기도 합니다. 또한 대상 폴더에 동일한 이름의 파일이 이미 있으면, REPLACE_EXISTING 옵션을 지정하지 않는 한 예외가 발생합니다.

예시: 파일을 다른 폴더로 이동

Path source = Path.of("data/report.txt");
Path target = Path.of("archive/report.txt");

Files.move(source, target);
System.out.println("파일이 이동되었습니다!");

기존 파일을 교체하며 이동

Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);

폴더 이동

Path oldDir = Path.of("data/old_reports");
Path newDir = Path.of("archive/old_reports");

Files.move(oldDir, newDir);

폴더 전체가, 포함된 파일과 하위 폴더까지 새 위치로 이동합니다.
단, 대상에 같은 이름의 폴더가 이미 있으면 오류가 발생합니다.

서로 다른 파일 시스템 간 이동

서로 다른 드라이브 간에 파일을 이동하면(예: "C:"에서 "D:"로) 내부적으로 복사 후 원본 삭제가 수행됩니다. 이 작업이 원자적으로 지원되지 않으면 AtomicMoveNotSupportedException이 발생할 수 있습니다.

move와 copy의 차이

  • copy — 원본 파일/폴더는 그대로 남고, 복사본이 생성됩니다.
  • move — 원본 파일/폴더는 사라지고 새 항목만 남습니다.

3. 파일과 폴더 이름 변경

Java에는 ‘파일 이름 변경’ 전용 메서드가 없습니다. 이름 변경은 이동의 특수한 경우로, 같은 디렉터리에서 이름만 다른 새 경로를 지정하면 됩니다.

예시: 파일 이름 변경

"report.txt" 파일을 같은 폴더에서 "report_old.txt"로 이름만 바꾸려 한다고 가정해 봅시다:

Path dir = Path.of("data");
Path oldName = dir.resolve("report.txt");
Path newName = dir.resolve("report_old.txt");

Files.move(oldName, newName);
System.out.println("파일 이름이 변경되었습니다!");

중요한 유의사항

대상 디렉터리에 지정한 이름의 파일이나 폴더가 이미 존재하면 메서드는 예외를 던집니다. 이를 우회하여 교체를 허용하려면 옵션 StandardCopyOption.REPLACE_EXISTING을 사용할 수 있습니다.

예시:

Path source = Paths.get("old_name.txt");
Path target = Paths.get("new_name.txt");

// 파일 이름을 변경합니다. 이미 존재하면 교체합니다.
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);

이 예시에서는 "old_name.txt"가 "new_name.txt"로 이름이 바뀝니다. 폴더에 동일한 이름의 파일이 이미 있었다면 덮어쓰게 됩니다.

폴더 이름 변경

Path oldDir = Path.of("data/old_reports");
Path newDir = Path.of("data/archived_reports");

Files.move(oldDir, newDir);
System.out.println("폴더 이름이 변경되었습니다!");

4. 복사, 이동, 이름 변경 시 오류 처리

파일 시스템 작업에서는 예기치 않은 상황이 자주 발생합니다. 대표적인 문제는 다음과 같습니다:

파일이 이미 존재합니다.
예외: FileAlreadyExistsException. 해결: 덮어쓰려면 REPLACE_EXISTING을 사용하세요.

파일 또는 폴더가 다른 프로세스에서 사용 중입니다.
예외: IOException. 예를 들어, 파일이 다른 프로그램에서 열려 있을 수 있습니다.

파일이나 폴더에 접근 권한이 없습니다.
예외: AccessDeniedException. 사용자 권한 문제입니다.

서로 다른 파일 시스템 간 이동.
예외: AtomicMoveNotSupportedException. 모든 파일 시스템이 원자적 이동을 지원하지는 않습니다.

대상 폴더가 존재하지 않습니다.
복사/이동 전에 대상 폴더가 미리 생성되어 있는지 확인하세요!

오류 처리 예시

try {
    Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
} catch (FileAlreadyExistsException e) {
    System.out.println("대상 파일이 이미 존재합니다: " + target);
} catch (AtomicMoveNotSupportedException e) {
    System.out.println("원자적 이동이 지원되지 않습니다: " + e.getMessage());
} catch (IOException e) {
    System.out.println("이동 중 오류: " + e.getMessage());
}

5. 실전 팁

대상 파일/폴더 존재 여부 확인

복사나 이동 전에 대상 경로가 이미 사용 중인지 확인하는 것이 좋습니다:

if (Files.exists(target)) {
    System.out.println("파일이 이미 있으므로 덮어쓰지 않습니다.");
} else {
    Files.copy(source, target);
}

안전한 작업을 위한 임시 파일 사용

중요한 파일을 갱신하는 등의 복잡한 작업에서는 임시 파일을 자주 사용합니다 — 먼저 임시 파일로 복사한 뒤, 본 파일을 교체합니다:

Path temp = Path.of("data/report.tmp");
Files.copy(source, temp, StandardCopyOption.REPLACE_EXISTING);
Files.move(temp, target, StandardCopyOption.REPLACE_EXISTING);

이 방식은 장애 발생 시 데이터 손실 위험을 최소화합니다.

예시: 교체 전에 파일 백업 만들기

Path file = Path.of("data/report.txt");
Path backup = Path.of("data/report_backup.txt");

if (Files.exists(file)) {
    Files.copy(file, backup, StandardCopyOption.REPLACE_EXISTING);
    System.out.println("백업이 생성되었습니다.");
}

6. 표: 주요 메서드와 옵션

작업 Java NIO 메서드 특징
복사
Files.copy(source, target, ...)
폴더의 내용을 복사하지 않습니다!
이동
Files.move(source, target, ...)
이름 변경에 사용할 수 있음
이름 변경
Files.move(source, target, ...)
같은 디렉터리 내의 새 경로
덮어쓰기
StandardCopyOption.REPLACE_EXISTING
대상 파일/폴더를 덮어씀
확인
Files.exists(path)
파일/폴더 존재 여부 확인

7. 복사, 이동, 이름 변경 시 자주 하는 실수

오류 №1: 존재하지 않는 폴더로 파일을 복사하려 함. 대상 디렉터리가 생성되어 있지 않으면 NoSuchFileException이 발생합니다. 해결: Files.createDirectories로 폴더를 먼저 생성하세요.

오류 №2: Files.copy로 폴더 전체를 복사하려 함. 메서드는 폴더의 “빈 껍데기”만 복사하고 내용을 복사하지 않습니다. 전체 복사를 위해서는 재귀 순회가 필요합니다.

오류 №3: 기존 파일 처리 미흡. REPLACE_EXISTING을 전달하지 않고 대상에 파일이 이미 있으면 예외가 발생합니다. 이 경우를 명시적으로 처리하세요.

오류 №4: 새 이름의 파일이 이미 존재하는데 이름을 바꾸려 함. 마찬가지로 FileAlreadyExistsException이 발생합니다. 이름 변경 전에 존재 여부를 확인하세요.

오류 №5: 서로 다른 파일 시스템 간 이동. 경우에 따라 작업이 “원자적”으로 지원되지 않아 AtomicMoveNotSupportedException이 발생합니다. 이때는 원자성 없이 일반 이동을 사용하세요.

오류 №6: 권한 부족 또는 파일 잠금. 파일이 다른 프로그램에서 열려 있거나 읽기/쓰기 권한이 없으면 AccessDeniedException 또는 IOException이 발생합니다. 항상 이러한 예외를 처리하세요.

1
과제
JAVA 25 SELF, 레벨 40, 레슨 1
잠금
새 보고서를 아카이브로 이동하기 📦
새 보고서를 아카이브로 이동하기 📦
1
과제
JAVA 25 SELF, 레벨 40, 레슨 1
잠금
오래된 문서 이름 변경 📝
오래된 문서 이름 변경 📝
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION