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);
표: 주요 복사 옵션
| 옵션 | 설명 |
|---|---|
|
대상 파일이 이미 있으면 덮어씀 |
|
속성 복사(생성 날짜 등) |
|
원자적 이동(오직 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 메서드 | 특징 |
|---|---|---|
| 복사 | |
폴더의 내용을 복사하지 않습니다! |
| 이동 | |
이름 변경에 사용할 수 있음 |
| 이름 변경 | |
같은 디렉터리 내의 새 경로 |
| 덮어쓰기 | |
대상 파일/폴더를 덮어씀 |
| 확인 | |
파일/폴더 존재 여부 확인 |
7. 복사, 이동, 이름 변경 시 자주 하는 실수
오류 №1: 존재하지 않는 폴더로 파일을 복사하려 함. 대상 디렉터리가 생성되어 있지 않으면 NoSuchFileException이 발생합니다. 해결: Files.createDirectories로 폴더를 먼저 생성하세요.
오류 №2: Files.copy로 폴더 전체를 복사하려 함. 메서드는 폴더의 “빈 껍데기”만 복사하고 내용을 복사하지 않습니다. 전체 복사를 위해서는 재귀 순회가 필요합니다.
오류 №3: 기존 파일 처리 미흡. REPLACE_EXISTING을 전달하지 않고 대상에 파일이 이미 있으면 예외가 발생합니다. 이 경우를 명시적으로 처리하세요.
오류 №4: 새 이름의 파일이 이미 존재하는데 이름을 바꾸려 함. 마찬가지로 FileAlreadyExistsException이 발생합니다. 이름 변경 전에 존재 여부를 확인하세요.
오류 №5: 서로 다른 파일 시스템 간 이동. 경우에 따라 작업이 “원자적”으로 지원되지 않아 AtomicMoveNotSupportedException이 발생합니다. 이때는 원자성 없이 일반 이동을 사용하세요.
오류 №6: 권한 부족 또는 파일 잠금. 파일이 다른 프로그램에서 열려 있거나 읽기/쓰기 권한이 없으면 AccessDeniedException 또는 IOException이 발생합니다. 항상 이러한 예외를 처리하세요.
GO TO FULL VERSION