1. 기본 속성 읽기: BasicFileAttributes
파일이나 폴더를 이야기할 때 이름이나 크기만을 의미하지 않습니다. 각 파일에는 “여권”과도 같은 속성 집합이 있으며, 여기에 다음이 포함됩니다:
- 생성 시간
- 마지막 수정 시간
- 마지막 접근 시간
- 크기
- 접근 권한 (누가 읽기, 쓰기, 실행할 수 있는지)
- 소유자 정보 (Unix)
- “숨김”, “읽기 전용” 등의 플래그
Java에서는 이들 속성을 다루기 위한 편리하고 강력한 API가 패키지 java.nio.file.attribute에 있습니다. 플랫폼 의존 코드를 작성할 필요가 없습니다. 필요한 것은 표준 라이브러리에 모두 있습니다.
먼저 필요한 클래스를 import합니다:
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.IOException;
기본 파일 속성은 어떻게 가져올까요?
Files.readAttributes 메서드를 사용합니다:
Path path = Paths.get("example.txt");
try {
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
System.out.println("생성됨: " + attrs.creationTime());
System.out.println("수정됨: " + attrs.lastModifiedTime());
System.out.println("마지막 접근: " + attrs.lastAccessTime());
System.out.println("크기: " + attrs.size());
System.out.println("디렉터리인가요? " + attrs.isDirectory());
System.out.println("일반 파일인가요? " + attrs.isRegularFile());
System.out.println("심볼릭 링크인가요? " + attrs.isSymbolicLink());
} catch (IOException e) {
System.out.println("속성 읽기 중 오류: " + e.getMessage());
}
집을 검사하러 온 검사관을 상상해 보세요. 문이 있는지(파일이 존재하는지)만 보는 게 아니라, “집은 언제 지었나요? 마지막으로 수리는 언제 했나요? 집주인은 누구인가요?”라고 묻습니다.
BasicFileAttributes 속성 요약
| 속성 | 반환 내용 |
|---|---|
|
파일/폴더의 생성 날짜와 시간 |
|
마지막 수정 날짜와 시간 |
|
마지막 접근 날짜와 시간 |
|
파일 크기(바이트) |
|
디렉터리인가? |
|
일반 파일인가? |
|
심볼릭 링크인가? |
2. 확장 속성: POSIX와 DOS
POSIX 속성(Linux, macOS 및 기타 Unix 계열 OS)
Unix 시스템에서는 접근 권한, 소유자, 그룹과 같은 확장 정보를 얻을 수 있습니다.
try {
PosixFileAttributes posixAttrs = Files.readAttributes(path, PosixFileAttributes.class);
System.out.println("소유자: " + posixAttrs.owner().getName());
System.out.println("그룹: " + posixAttrs.group().getName());
System.out.println("권한: " + PosixFilePermissions.toString(posixAttrs.permissions()));
} catch (UnsupportedOperationException e) {
System.out.println("이 OS에서는 POSIX 속성을 지원하지 않습니다.");
} catch (IOException e) {
System.out.println("POSIX 속성 읽기 중 오류: " + e.getMessage());
}
참고: Windows에서는 이 코드는 UnsupportedOperationException을 던집니다. 정상 동작입니다.
DOS 속성(Windows)
Windows에서는 “읽기 전용”, “숨김”, “아카이브”, “시스템” 플래그를 다룰 수 있습니다:
try {
DosFileAttributes dosAttrs = Files.readAttributes(path, DosFileAttributes.class);
System.out.println("숨김: " + dosAttrs.isHidden());
System.out.println("읽기 전용: " + dosAttrs.isReadOnly());
System.out.println("시스템: " + dosAttrs.isSystem());
System.out.println("아카이브: " + dosAttrs.isArchive());
} catch (UnsupportedOperationException e) {
System.out.println("이 OS에서는 DOS 속성을 지원하지 않습니다.");
} catch (IOException e) {
System.out.println("DOS 속성 읽기 중 오류: " + e.getMessage());
}
3. 파일 속성 변경
남의 여권을 읽는 것과 생년월일이나 성을 바꾸는 것은 전혀 다른 일입니다! Java에서는 (적절한 권한이 있다면) 파일의 속성을 변경할 수도 있습니다.
마지막 수정 시간 변경
import java.nio.file.attribute.FileTime;
Path file = Paths.get("example.txt");
try {
FileTime newTime = FileTime.fromMillis(System.currentTimeMillis() - 24 * 60 * 60 * 1000); // 1일 전
Files.setLastModifiedTime(file, newTime);
System.out.println("마지막 수정 시간이 변경되었습니다!");
} catch (IOException e) {
System.out.println("시간 변경 중 오류: " + e.getMessage());
}
접근 권한 변경(POSIX)
Unix 시스템에서만 가능합니다! 예를 들어, 모든 사용자가 실행할 수 있도록 설정하기:
try {
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-xr-x");
Files.setPosixFilePermissions(file, perms);
System.out.println("권한이 변경되었습니다!");
} catch (UnsupportedOperationException e) {
System.out.println("이 OS에서는 POSIX 권한을 지원하지 않습니다.");
} catch (IOException e) {
System.out.println("권한 변경 중 오류: " + e.getMessage());
}
문자열 "rwxr-xr-x" 설명:
- r — read(읽기)
- w — write(쓰기)
- x — execute(실행)
- 첫 세 글자는 소유자, 다음은 그룹, 마지막은 그 외 사용자입니다.
숨김/읽기 전용 상태 변경(DOS 속성, Windows)
파일을 숨김으로 설정:
try {
Files.setAttribute(file, "dos:hidden", true);
System.out.println("파일이 숨김으로 설정되었습니다(Windows)!");
} catch (UnsupportedOperationException e) {
System.out.println("이 OS에서는 DOS 속성을 지원하지 않습니다.");
} catch (IOException e) {
System.out.println("속성 변경 중 오류: " + e.getMessage());
}
파일을 “읽기 전용”으로 설정:
try {
Files.setAttribute(file, "dos:readonly", true);
System.out.println("파일이 이제 읽기 전용입니다(Windows)!");
} catch (UnsupportedOperationException e) {
System.out.println("이 OS에서는 DOS 속성을 지원하지 않습니다.");
} catch (IOException e) {
System.out.println("속성 변경 중 오류: " + e.getMessage());
}
4. 접근 권한 확인
가끔은 파일을 읽기, 쓰기, 실행할 수 있는지 빠르게 확인하는 것이 중요합니다:
Path file = Paths.get("example.txt");
System.out.println("읽기 가능: " + Files.isReadable(file));
System.out.println("쓰기 가능: " + Files.isWritable(file));
System.out.println("실행 가능: " + Files.isExecutable(file));
모든 플랫폼에서 동일하게 동작하지만, 실제 동작은 OS와 보안 설정에 따라 달라질 수 있습니다.
5. 실습: 파일 상세 정보 출력
파일 경로를 받아 가능한 한 많은 정보를 보여 주고 몇 가지 속성 변경도 시도하는 작은 프로그램을 작성해 보겠습니다.
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.util.Set;
import java.io.IOException;
public class FileAttributesDemo {
public static void main(String[] args) throws IOException {
Path path = Paths.get("example.txt");
if (!Files.exists(path)) {
System.out.println("파일을 찾을 수 없습니다!");
return;
}
// 기본 속성
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
System.out.println("이름: " + path.getFileName());
System.out.println("경로: " + path.toAbsolutePath());
System.out.println("크기: " + attrs.size() + " 바이트");
System.out.println("생성됨: " + attrs.creationTime());
System.out.println("수정됨: " + attrs.lastModifiedTime());
System.out.println("마지막 접근: " + attrs.lastAccessTime());
System.out.println("디렉터리인가요? " + attrs.isDirectory());
System.out.println("일반 파일인가요? " + attrs.isRegularFile());
// 접근 권한 확인
System.out.println("읽기 가능: " + Files.isReadable(path));
System.out.println("쓰기 가능: " + Files.isWritable(path));
System.out.println("실행 가능: " + Files.isExecutable(path));
// 수정 시간 변경 시도
FileTime now = FileTime.fromMillis(System.currentTimeMillis());
Files.setLastModifiedTime(path, now);
System.out.println("마지막 수정 시간이 업데이트되었습니다!");
// 파일을 숨김으로 설정 시도(지원되는 경우)
try {
Files.setAttribute(path, "dos:hidden", true);
System.out.println("파일이 숨김으로 설정되었습니다(OS가 지원하는 경우).");
} catch (UnsupportedOperationException e) {
System.out.println("이 OS에서는 숨김 파일을 지원하지 않습니다.");
}
// POSIX 권한 출력 시도(지원되는 경우)
try {
PosixFileAttributes posixAttrs = Files.readAttributes(path, PosixFileAttributes.class);
System.out.println("소유자: " + posixAttrs.owner().getName());
System.out.println("권한: " + PosixFilePermissions.toString(posixAttrs.permissions()));
} catch (UnsupportedOperationException e) {
System.out.println("이 OS에서는 POSIX 속성을 지원하지 않습니다.");
}
}
}
6. 유용한 팁
크로스플랫폼 차이와 팁
- 모든 OS에서 모든 속성을 사용할 수 있는 것은 아닙니다! Windows에는 POSIX 권한이 없고, Linux에는 DOS 속성이 없습니다.
- 항상 try-catch를 사용하세요! 메서드는 UnsupportedOperationException이나 IOException을 던질 수 있습니다.
- 접근 권한이 항상 “rwx”만은 아닙니다! Windows의 권한 모델은 다르며, “읽기 전용”은 OS의 보안 정책으로 설정될 수 있습니다.
- 숨김 파일의 개념은 상대적입니다. Unix에서는 이름이 점으로 시작하면(.hidden) 숨김이고, Windows에서는 속성 dos:hidden이 설정되면 숨김입니다.
표: 어떤 속성이 어디에서 가능한가
| 속성 | Windows (dos:*) | Linux/macOS (posix:*) |
|---|---|---|
| 생성 시간 | + | + |
| 마지막 수정 시간 | + | + |
| 마지막 접근 시간 | + | + |
| 숨김 파일 | + | 점으로 시작하는 이름만 |
| 읽기 전용 | + | + |
| 접근 권한 (rwx) | - | + |
| 소유자, 그룹 | - | + |
| 아카이브, 시스템 | + | - |
7. 파일 속성 작업 시 흔한 실수
오류 №1: Windows에서 POSIX 속성을 읽거나 변경하려는 시도. Windows에서는 UnsupportedOperationException이 발생합니다. 크로스플랫폼 코드를 작성할 때는 항상 이 예외를 처리하세요.
오류 №2: 다른 프로세스가 열고 있는 파일의 수정 시간을 변경하려는 경우. 일부 시스템에서는 파일이 잠겨 있어 작업이 실패할 수 있습니다.
오류 №3: “파일 숨기기”가 모든 OS에서 동일하게 동작한다고 기대하는 경우. Unix에서는 이름이 점으로 시작하는(.gitignore) 파일이 숨김이고, Windows에서는 속성 dos:hidden이 설정되어야 합니다. 이 접근 방식을 혼동하지 마세요.
오류 №4: 작업 전에 파일 존재 여부를 확인하지 않는 경우. 파일이 없으면 속성을 가져오거나 변경하려 할 때 NoSuchFileException이 발생합니다.
오류 №5: 권한 검사를 하지 않는 경우. 사용자에게 속성 변경 권한이 없으면 작업이 실패합니다. 변경 전에 Files.isWritable(path)를 확인하세요.
GO TO FULL VERSION