상세 컨텐츠

본문 제목

C# 디렉토리 및 파일 생성 완벽 가이드 (2025년 최신)

컴퓨터 언어/C#

by cepiloth 2025. 5. 29. 16:38

본문

728x90

📋 목차

  1. 기본 개념
  2. 디렉토리 생성
  3. 파일 생성 및 쓰기
  4. 실무 예제 코드
  5. 예외 처리
  6. 성능 최적화
  7. 자주 묻는 질문

🎯 기본 개념

C#에서 파일과 디렉토리를 다룰 때 주로 사용하는 네임스페이스와 클래스들:

  • System.IO 네임스페이스
  • Directory 클래스: 디렉토리 관련 정적 메서드 제공
  • DirectoryInfo 클래스: 특정 디렉토리에 대한 인스턴스 메서드 제공
  • File 클래스: 파일 관련 정적 메서드 제공
  • FileInfo 클래스: 특정 파일에 대한 인스턴스 메서드 제공

📁 디렉토리 생성

기본 디렉토리 생성

using System;
using System.IO;

// 방법 1: Directory.CreateDirectory (정적 메서드)
string dirPath = @"C:\MyApp\Logs";
DirectoryInfo createdDir = Directory.CreateDirectory(dirPath);
Console.WriteLine($"디렉토리 생성됨: {createdDir.FullName}");

// 방법 2: DirectoryInfo 클래스 사용
DirectoryInfo dirInfo = new DirectoryInfo(@"C:\MyApp\Data");
if (!dirInfo.Exists)
{
    dirInfo.Create();
    Console.WriteLine("디렉토리가 생성되었습니다.");
}

중첩 디렉토리 생성

// 여러 단계의 디렉토리를 한 번에 생성
string nestedPath = @"C:\MyApp\Year2025\Month05\Day29";
Directory.CreateDirectory(nestedPath);
// 존재하지 않는 모든 상위 디렉토리도 자동으로 생성됩니다.

현재 실행 경로 기준 디렉토리 생성

// 현재 실행 디렉토리 기준으로 상대 경로 사용
string relativePath = Path.Combine("Data", "Logs", DateTime.Now.ToString("yyyy-MM"));
DirectoryInfo dir = Directory.CreateDirectory(relativePath);
Console.WriteLine($"생성된 경로: {dir.FullName}");

📄 파일 생성 및 쓰기

기본 파일 생성 및 쓰기

using System;
using System.IO;
using System.Text;

public class FileManager
{
    public void CreateLogFile(string directoryPath, string content)
    {
        try
        {
            // 1. 디렉토리 생성 (존재하지 않을 경우)
            Directory.CreateDirectory(directoryPath);
            
            // 2. 파일 경로 생성
            string fileName = $"log_{DateTime.Now:yyyyMMdd_HHmmss}.txt";
            string filePath = Path.Combine(directoryPath, fileName);
            
            // 3. 파일 생성 및 내용 쓰기
            using (StreamWriter writer = new StreamWriter(filePath, append: true, Encoding.UTF8))
            {
                writer.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {content}");
            }
            
            Console.WriteLine($"로그 파일 생성: {filePath}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"파일 생성 오류: {ex.Message}");
        }
    }
}

최신 .NET 방식 (File.WriteAllTextAsync)

using System;
using System.IO;
using System.Threading.Tasks;

public class ModernFileManager
{
    public async Task CreateFileAsync(string directoryPath, string fileName, string content)
    {
        try
        {
            // 디렉토리 생성
            Directory.CreateDirectory(directoryPath);
            
            // 파일 경로
            string filePath = Path.Combine(directoryPath, fileName);
            
            // 비동기 파일 쓰기 (.NET 6.0+)
            await File.WriteAllTextAsync(filePath, content);
            
            Console.WriteLine($"파일 생성 완료: {filePath}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"파일 생성 실패: {ex.Message}");
        }
    }
}

💼 실무 예제 코드

로그 시스템 구현

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

public class LogManager
{
    private readonly string _baseLogPath;
    private readonly object _lockObject = new object();
    
    public LogManager(string baseLogPath = "Logs")
    {
        _baseLogPath = baseLogPath;
    }
    
    public void WriteLog(string message, LogLevel level = LogLevel.Info)
    {
        try
        {
            // 날짜별 디렉토리 생성
            string dateFolder = DateTime.Now.ToString("yyyy-MM");
            string logDirectory = Path.Combine(_baseLogPath, dateFolder);
            Directory.CreateDirectory(logDirectory);
            
            // 파일명 생성
            string fileName = $"{DateTime.Now:yyyyMMdd}_{level}.log";
            string filePath = Path.Combine(logDirectory, fileName);
            
            // Thread-safe 파일 쓰기
            lock (_lockObject)
            {
                using (StreamWriter writer = new StreamWriter(filePath, append: true))
                {
                    string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] [{level}] {message}";
                    writer.WriteLine(logEntry);
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"로그 쓰기 실패: {ex.Message}");
        }
    }
    
    public async Task WriteLogAsync(string message, LogLevel level = LogLevel.Info)
    {
        try
        {
            string dateFolder = DateTime.Now.ToString("yyyy-MM");
            string logDirectory = Path.Combine(_baseLogPath, dateFolder);
            Directory.CreateDirectory(logDirectory);
            
            string fileName = $"{DateTime.Now:yyyyMMdd}_{level}.log";
            string filePath = Path.Combine(logDirectory, fileName);
            
            string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] [{level}] {message}{Environment.NewLine}";
            
            // 비동기 파일 쓰기
            await File.AppendAllTextAsync(filePath, logEntry);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"비동기 로그 쓰기 실패: {ex.Message}");
        }
    }
}

public enum LogLevel
{
    Info,
    Warning,
    Error,
    Debug
}

사용 예제

class Program
{
    static async Task Main(string[] args)
    {
        var logManager = new LogManager("C:\\MyApp\\Logs");
        
        // 동기 방식
        logManager.WriteLog("애플리케이션 시작", LogLevel.Info);
        logManager.WriteLog("경고 메시지", LogLevel.Warning);
        
        // 비동기 방식
        await logManager.WriteLogAsync("비동기 로그 테스트", LogLevel.Debug);
        
        Console.WriteLine("로그 작성 완료!");
    }
}

⚠️ 예외 처리

주요 예외 상황과 처리 방법

public class SafeFileManager
{
    public bool CreateDirectoryAndFile(string directoryPath, string fileName, string content)
    {
        try
        {
            // 디렉토리 생성
            Directory.CreateDirectory(directoryPath);
            
            string filePath = Path.Combine(directoryPath, fileName);
            
            // 파일 쓰기
            File.WriteAllText(filePath, content);
            
            return true;
        }
        catch (UnauthorizedAccessException)
        {
            Console.WriteLine("권한이 없습니다. 관리자 권한으로 실행하거나 다른 경로를 사용하세요.");
            return false;
        }
        catch (DirectoryNotFoundException)
        {
            Console.WriteLine("지정된 경로의 일부를 찾을 수 없습니다.");
            return false;
        }
        catch (IOException ex)
        {
            Console.WriteLine($"I/O 오류 발생: {ex.Message}");
            return false;
        }
        catch (ArgumentException)
        {
            Console.WriteLine("잘못된 경로 형식입니다.");
            return false;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"예상치 못한 오류: {ex.Message}");
            return false;
        }
    }
}

🚀 성능 최적화

1. 대용량 파일 처리

public async Task WriteLargeFileAsync(string filePath, IEnumerable<string> lines)
{
    using (StreamWriter writer = new StreamWriter(filePath, append: false))
    {
        foreach (string line in lines)
        {
            await writer.WriteLineAsync(line);
        }
    }
}

2. 버퍼링을 이용한 성능 향상

public void WriteWithBuffer(string filePath, string[] data)
{
    using (FileStream fs = new FileStream(filePath, FileMode.Create))
    using (BufferedStream bs = new BufferedStream(fs, bufferSize: 65536)) // 64KB 버퍼
    using (StreamWriter writer = new StreamWriter(bs))
    {
        foreach (string item in data)
        {
            writer.WriteLine(item);
        }
    }
}

❓ 자주 묻는 질문

Q1: 디렉토리가 이미 존재할 때 어떻게 되나요?

A: Directory.CreateDirectory()는 디렉토리가 이미 존재해도 예외를 발생시키지 않습니다. 안전하게 여러 번 호출할 수 있습니다.

Q2: 파일이 사용 중일 때 어떻게 처리하나요?

A: IOException이 발생할 수 있습니다. 재시도 로직을 구현하거나 다른 파일명을 사용하세요.

public string GetAvailableFileName(string directoryPath, string baseFileName)
{
    string filePath = Path.Combine(directoryPath, baseFileName);
    int counter = 1;
    
    while (File.Exists(filePath))
    {
        string nameWithoutExt = Path.GetFileNameWithoutExtension(baseFileName);
        string extension = Path.GetExtension(baseFileName);
        string newFileName = $"{nameWithoutExt}_{counter}{extension}";
        filePath = Path.Combine(directoryPath, newFileName);
        counter++;
    }
    
    return filePath;
}

Q3: 크로스 플랫폼 호환성은 어떻게 보장하나요?

A: Path.Combine(), Path.DirectorySeparatorChar 등을 사용하여 플랫폼별 경로 구분자를 자동으로 처리하세요.

// 올바른 방법 - 모든 플랫폼에서 동작
string path = Path.Combine("Users", "Documents", "MyApp");

// 잘못된 방법 - Windows에서만 동작
string wrongPath = "Users\\Documents\\MyApp";

📚 추가 학습 자료


이 포스트가 도움이 되었다면 댓글로 피드백을 남겨주세요! 🙏

관련 포스트:

728x90
반응형

관련글 더보기

댓글 영역