기본 콘텐츠로 건너뛰기

[C#] 경로



테스트 폴더 구조

F:\MYTESTDIR
│  RandomText.txt
│  시트.xlsx
│  
├─Dir01
│      231108 Coordinate System 1.png
│      
└─Dir02
    │  tt.cs
    │  
    └─SubDir
            back.jpg
            예시 이미지.jpg

기본 함수, 필드

Path.DirectorySeparatorChar

현재 OS에서 사용하는 경로 구분자를 반환. Windows의 경우 역슬래시(\)를 반환

참고 : https://learn.microsoft.com/en-us/dotnet/api/System.IO.Path.DirectorySeparatorChar?view=net-5.0


추가

아래와 같은 함수를 이용하면, 경로 구분자를 정렬할 수 있다. (문자 교체)

1
2
3
4
5
6
public static string RearrangePathSeparateChar(string src)  
{  
    src = src.Replace('\\', Path.DirectorySeparatorChar);  
    src = src.Replace('/', Path.DirectorySeparatorChar);  
    return src;  
}
cs


Path.Combine(String, String)

파라미터로 들어온 문자열 사이에 경로 구분자를 넣어 합친다. 파라미터에 입력받는 문자열에 경로 구분자 (역슬래시, 슬래시)가 포함되면 제대로 작동하지 않는 경우가 존재하니 주의.

string testRootPath = @"F:\MyTestDir";
string result = Path.Combine(testRootPath, "Dir02""SubDir""예시 이미지.jpg");
Console.WriteLine(@$"[Path.Combine] : {result}");
 
// 출력 결과 : [Path.Combine] : F:\MyTestDir\Dir02\SubDir\예시 이미지.jpg
cs


참고 : https://learn.microsoft.com/en-us/dotnet/api/system.io.path.combine?view=net-5.0


Directory.GetFiles(String)

파라미터로 입력받은 경로에 있는 파일들의 절대 경로를 추출한다.

string testRootPath = @"F:\MyTestDir";
string[] testFiles = Directory.GetFiles(testRootPath);
int testFilesLength = testFiles.Length;
 
for (int i = 0; i < testFilesLength; i++)
{
    var eachFileAbsPath = testFiles[i];
    Console.WriteLine(@$"[Directory.GetFiles No {i}] : {eachFileAbsPath}");
}
 
// 출력 결과
// [Directory.GetFiles No 0] : F:\MyTestDir\RandomText.txt
// [Directory.GetFiles No 1] : F:\MyTestDir\시트.xlsx
cs




Directory.GetDirectories(String)

파리미터로 입력받은 경로에 있는 디렉토리의 절대 경로를 추출한다.

string testRootPath = @"F:\MyTestDir";
string[] testDir = Directory.GetDirectories(testRootPath);
int testDirLength = testDir.Length;
 
for (int j = 0; j < testDirLength; j++)
{
    var eachDirAbsPath = testDir[j];
    Console.WriteLine(@$"[Directory.GetDirectories No {j}] : {eachDirAbsPath}");
}
 
// 출력 결과
// [Directory.GetDirectories No 0] : F:\MyTestDir\Dir01
// [Directory.GetDirectories No 1] : F:\MyTestDir\Dir02
cs

Path.GetFileName(String)
Path.GetFileNameWithoutExtension(String)

파리미터로 입력받은 문자열에서 마지막 디렉토리 다음 뒷부분의 문자열을 가져온다. 즉, 파일 이름을 가져온다. GetFileName의 경우 확장자가 포함되며, GetFileNameWithoutExtension은 순수한 파일이름만 가져온다.
파일이 아닌 디렉토리인 경우 빈 문자열, 파라미터가 null이면 null을 반환한다.

string testFile = @"F:\MyTestDir\Dir02\SubDir\back.jpg";
 
string fileNameFull = Path.GetFileName(testFile);
string fileNameOnly = Path.GetFileNameWithoutExtension(testFile);
 
Console.WriteLine(@$"[Path.GetFileName] : {fileNameFull}");
Console.WriteLine(@$"[Path.GetFileNameWithoutExtension] : {fileNameOnly}");
 
// 출력 결과
// [Path.GetFileName] : back.jpg
// [Path.GetFileNameWithoutExtension] : back
cs


Path.GetDirectoryName(String)

지정된 경로에 대한 디렉터리 정보를 반환. 즉, 선택한 파일 또는 폴더가 있는 폴더의 절대경로를 반환해준다. 단, 아래 예시 코드에서 보면 드라이브를 선택하면 빈 문자열이 반환되는 듯 하다. 


string filePath = @"C:\MyDir\MySubDir\myfile.ext";
string directoryName;
int i = 0;
 
while (filePath != null)
{
    directoryName = Path.GetDirectoryName(filePath);
    Console.WriteLine("GetDirectoryName('{0}') returns '{1}'",
        filePath, directoryName);
    filePath = directoryName;
    if (i == 1)
    {
        filePath = directoryName + @"\";  // this will preserve the previous path
    }
    i++;
}
/*
This code produces the following output:
GetDirectoryName('C:\MyDir\MySubDir\myfile.ext') returns 'C:\MyDir\MySubDir'
GetDirectoryName('C:\MyDir\MySubDir') returns 'C:\MyDir'
GetDirectoryName('C:\MyDir\') returns 'C:\MyDir'
GetDirectoryName('C:\MyDir') returns 'C:\'
GetDirectoryName('C:\') returns ''
*/
cs


응용

디렉토리 삭제



/// <summary>
/// 재귀 함수
/// </summary>
public static void DeleteDirectoryRecursive(string path)
{
    foreach (var directoryPath in Directory.GetDirectories(path))
    {
        DeleteDirectoryRecursive(directoryPath);
    }
 
    try
    {
        Directory.Delete(path, true);
    }
    catch (IOException)
    {
        Directory.Delete(path, true);
    }
    catch (UnauthorizedAccessException)
    {
        Directory.Delete(path, true);
    }
}
cs



순수하게 Directory.Delete 함수를 사용하면 아래와 같은 이유로 제대로 작동하지 않을 수 있다. 
  • System.IO.IOException : The directory is not empty 
  • 경로를 찾지 못함
  • 읽기 전용, 권한(?) 문제
  • 파일, 폴더가 이미 삭제되었다는 것을 인지하기도 전에 삭제를 시도 ← 대부분 발생
  • 다른 프로그램(Explorer, 백신)과 충돌
  • 기타 등등 (?)
Thread.Sleep(ms) 주는 방법도 있지만, 위 함수 같이 Exception을 이용할 것을 권장한다. Exception이 발생해도 다행히 파일, 폴더는 잘 삭제한다.


선택한 폴더 내부에 있는 모든 파일, 폴더 복사



/// <summary>
/// 재귀함수
/// </summary>
public static void CopyDirectoryAndInner(string sourceDirPath, string destinationDirPath, bool overwrite = true)
{
    if (!Directory.Exists(destinationDirPath))
        Directory.CreateDirectory(destinationDirPath);
 
    //파일 복사
    foreach (var srcfile in Directory.GetFiles(sourceDirPath))
    {
        var destFile = Path.Combine(destinationDirPath, Path.GetFileName(srcfile));
        File.Copy(srcfile, destFile, overwrite);
    }
 
    //폴더 복사
    foreach (var srcSubDir in Directory.GetDirectories(sourceDirPath))
    {
        var destSubDir = Path.Combine(destinationDirPath, Path.GetFileName(srcSubDir));
        CopyDirectoryAndInner(srcSubDir, destSubDir);
    }
}
cs

추가

  File.Copy 함수 사용시 목표 경로까지 디렉토리가 없으면 (생성되어 있지 않는 경우) 복사는 실패하게 된다. Directory.CreateDirectory 함수를 이용하여 미리 디렉토리를 생성한 후, 파일을 복사하면 된다. Directory.CreateDirectory 함수는 파라미터로 입력받은 경로까지 디렉토리를 생성해준다.







댓글