1. 소개
정적 클래스들, 예를 들어 File 와 Directory 는 만능 스위스 아미 나이프처럼 항상 손에 닿는 도구라 빠르게 문제를 해결하지만 특정 객체에 묶여있지 않아요. 반면 FileInfo 와 DirectoryInfo 는 특정 파일이나 폴더를 위해 만들어진 개인화된 도구에 가깝습니다. 특정 객체에 대해 많은 정보를 알고 있고, 동일 객체에 대한 반복 작업에서 더 편리하고 유연하게 동작하죠.
인스턴스 클래스 는 특정 파일 시스템 객체에 대한 세부 정보를 보관합니다. 처음 속성을 로드한 이후에는(객체가 오래되지 않았다면) 다시 파일 시스템을 쿼리할 필요가 없을 수 있어요.
- FileInfo — 특정 파일 작업용.
- DirectoryInfo — 특정 디렉터리(폴더) 작업용.
이들은 파일/폴더의 자세한 정보(크기, 생성일, 확장자, 사용 가능한 속성 등)를 얻고 파일/폴더를 복사, 삭제, 이동 등 다양한 작업을 수행할 수 있는 속성과 메서드를 포함합니다.
FileInfo 와 DirectoryInfo 구조
두 클래스는 공통 추상 클래스인 FileSystemInfo 를 상속하므로 파일과 폴더를 동일한 방식으로 다루는 코드를 작성할 수 있습니다.
System.Object
|
System.MarshalByRefObject
|
System.IO.FileSystemInfo (추상 클래스)
| |
FileInfo DirectoryInfo
언제 인스턴스 클래스를 사용할까?
- 하나의 파일/폴더에 대해 많은 정보(크기, 수정일, 확장자, 속성 등)를 여러 번 사용해야 할 때.
- 디렉터리의 모든 파일/폴더를 순회하면서 각 객체를 '살아있는' 인스턴스로 다루고 싶을 때.
- 파일 시스템에 불필요하게 여러 번 접근하지 않는 것이 성능상 중요할 때(캐싱).
- 객체지향적인 코드 스타일(백업, 미디어 라이브러리, 파일 매니저 등)을 선호할 때.
FileInfo 또는 DirectoryInfo 인스턴스 생성 방법
using System.IO;
// 기존(또는 아직 없는!) 파일에 대한 FileInfo 객체 생성:
var fileInfo = new FileInfo("notes.txt");
// 폴더에 대한 DirectoryInfo 객체 생성:
var dirInfo = new DirectoryInfo(@"C:\Projects");
// 상대경로나 절대경로 모두 사용 가능!
중요: FileInfo 또는 DirectoryInfo 객체를 생성한다고 해서 파일/폴더가 실제로 생성되는 것은 아닙니다. 단지 기술(참조)일 뿐이에요.
2. FileInfo 작업
이 클래스의 주요 속성과 메서드를 정리해봅시다. 참고용 메모:
| 속성/메서드 | 반환 내용 | 사용 예 |
|---|---|---|
|
파일 이름 | |
|
전체 경로 | |
|
파일 크기(바이트) | |
|
부모 디렉터리 (DirectoryInfo) | |
|
파일이 실제로 존재하는지? | |
|
파일 확장자(.txt 등) | |
|
생성일 | |
|
최종 수정일 | |
|
읽기 전용 여부 | |
| 메서드 | ||
|
파일 복사 | |
|
파일 삭제 | |
|
파일 이동 | |
|
읽기용 스트림 열기 | |
|
쓰기용 스트림 열기 | |
예제: 파일 정보 얻기
간단한 모듈을 추가해서 FileInfo 로 파일의 상세 정보를 얻어봅시다.
Console.WriteLine("파일 이름을 입력하세요:");
string fileName = Console.ReadLine();
var file = new FileInfo(fileName);
if (file.Exists)
{
Console.WriteLine($"파일 이름: {file.Name}");
Console.WriteLine($"경로: {file.FullName}");
Console.WriteLine($"크기: {file.Length} 바이트");
Console.WriteLine($"확장자: {file.Extension}");
Console.WriteLine($"생성일: {file.CreationTime}");
Console.WriteLine($"마지막 수정: {file.LastWriteTime}");
// 추가: 부모 디렉터리 표시
Console.WriteLine($"부모 폴더: {file.DirectoryName}");
}
else
{
Console.WriteLine("파일을 찾을 수 없습니다.");
}
주의: 파일 내용을 읽는 것이 아니라 메타정보만 가져옵니다.
연습: 파일 복사 및 삭제
// ... 메인 메서드 내부에서 파일 정보 출력이 성공한 뒤:
Console.WriteLine("복사할 경로를 입력하세요:");
string copyPath = Console.ReadLine();
try
{
file.CopyTo(copyPath);
Console.WriteLine($"파일이 {copyPath} 로 성공적으로 복사되었습니다.");
}
catch (IOException ex)
{
Console.WriteLine($"파일을 복사할 수 없습니다: {ex.Message}");
}
// 이제 복사본을 삭제해볼게요
Console.WriteLine("복사본을 삭제하시겠습니까? (y/n):");
if (Console.ReadLine().Trim().ToLower() == "y")
{
var copyFile = new FileInfo(copyPath);
if (copyFile.Exists)
{
copyFile.Delete();
Console.WriteLine("복사본이 삭제되었습니다.");
}
}
3. DirectoryInfo 작업
DirectoryInfo 가 제공하는 기능들을 살펴봅시다:
| 속성/메서드 | 반환 내용 | 사용 예 |
|---|---|---|
|
폴더 이름 | |
|
전체 경로 | |
|
부모 폴더 (DirectoryInfo) | |
|
폴더가 존재하는지? | |
|
생성일 | |
|
수정일 | |
| 메서드 | ||
|
폴더 생성 | |
|
폴더 삭제 | |
|
파일 배열 (FileInfo 배열) | |
|
하위 폴더 배열 (DirectoryInfo 배열) | |
|
파일 열거 (IEnumerable<FileInfo>, 지연 모드) | |
|
폴더 이동 | |
예제: 파일과 폴더 순회
Console.WriteLine("폴더 경로를 입력하세요:");
string path = Console.ReadLine();
var dir = new DirectoryInfo(path);
if (!dir.Exists)
{
Console.WriteLine("폴더를 찾을 수 없습니다!");
return;
}
Console.WriteLine("\n--- 파일 ---");
foreach (var file in dir.GetFiles())
{
Console.WriteLine($"{file.Name} ({file.Length} 바이트)");
}
Console.WriteLine("\n--- 하위 폴더 ---");
foreach (var subDir in dir.GetDirectories())
{
Console.WriteLine(subDir.Name);
}
4. 유용한 팁
정적 메서드 vs 인스턴스 클래스
어떤 접근법을 쓸지 결정할 때: 한 번만 하는 '일회성' 동작이면 File.Exists(path) 또는 File.ReadAllText(path) 같은 정적 메서드가 더 간단하고 약간 더 빠릅니다. 오버헤드가 적기 때문이죠.
반면 파일/폴더에 대해 많은 정보를 얻거나 반복 연산을 해야 하거나 OOP 스타일로 코드를 쓰고 싶다면 FileInfo 와 DirectoryInfo 같은 인스턴스가 더 적합합니다.
두 접근법은 내부적으로 유사한 저수준 시스템 호출을 사용합니다. 하지만 인스턴스 클래스는 일부 속성(크기, 날짜, 속성 등)을 캐시해서 파일 시스템 접근 횟수를 줄여줍니다 — 특히 많은 파일을 순회할 때 유리합니다.
날짜/시간 처리에 관해
속성 CreationTime, LastWriteTime, LastAccessTime 은 DateTime 형식을 반환합니다.
Console.WriteLine($"파일 생성: {file.CreationTime:yyyy-MM-dd HH:mm:ss}");
Console.WriteLine($"마지막 수정: {file.LastWriteTime:yyyy-MM-dd HH:mm:ss}");
만약 파일이나 폴더가 인스턴스 생성 후 디스크에서 변경되었다면 캐시된 정보가 오래될 수 있습니다. 이 경우 file.Refresh() 를 호출해서 정보를 갱신하세요.
실용적인 조언
- 인스턴스 클래스는 파일 시스템 래퍼(백업, 미디어 라이브러리, 인덱서 등)를 만들 때 편리합니다.
- LINQ 와 함께 사용하면 크기, 날짜, 확장자 등으로 필터링 후 선택한 객체에 작업을 수행하기 좋습니다.
- 대량 작업 시에는 EnumerateFiles() 와 EnumerateDirectories() 를 GetFiles()/GetDirectories() 보다 선호하세요 — 지연 열거가 메모리를 절약하고 처리 시작 속도를 높입니다.
정적 방법과 인스턴스 방식 비교
| 정적 메서드 | 인스턴스 클래스 | |
|---|---|---|
| 문법 | |
|
| 캐싱 | 없음 | 있음 |
| 많은 정보 필요 여부 | 여러 메서드를 호출해야 함 | 객체에 포함되어 있음 |
| OOP 스타일 | 아님 | 예 |
| 대량 작업 | 불편 | 편리 |
| 스트림 작업 | 가능 | 가능 |
정보와 객체 갱신
FileInfo / DirectoryInfo 객체는 처음 속성에 접근할 때 값을 캐시합니다. 만약 인스턴스 생성 이후 파일/폴더가 디스크에서 변경되었다면 .Refresh() 를 호출해 정보를 갱신하세요.
var file = new FileInfo("notes.txt");
long oldSize = file.Length;
// 이 사이에 파일이 외부에서 변경될 수 있음
file.Refresh();
long newSize = file.Length;
파일 시스템을 감시하는 프로그램을 만드는 경우 이 메커니즘이 중요합니다.
5. 인스턴스 클래스 사용 시 흔한 실수
오해: new FileInfo("file.txt") 를 하면 파일이 이미 존재한다고 생각하는 것. 실제로는 그렇지 않습니다 — 파일은 명시적으로 쓰거나 Create() 를 호출해야 생깁니다.
존재하지 않는 파일의 속성을 얻으려 하면 일부 속성은 기본값(예: 크기 0) 을 반환할 수 있지만, 읽기 스트림을 열려고 하면 예외가 발생합니다.
폴더도 마찬가지입니다: DirectoryInfo 를 생성한다고 해서 디스크에 실제 폴더가 있다는 보장은 없습니다. 폴더가 필요하다면 Create() 등을 호출하세요.
GO TO FULL VERSION