문제

C#에서 정적 멤버 함수를 작성하려고 하거나 .NET Framework에서 파일 시스템이 지정하는 파일 경로를 다시 지정하는 함수를 찾으려고 합니다.

예:

string filepath = @"C:\temp.txt";
filepath = FileUtility.RecaseFilepath(filepath);

// filepath = C:\Temp.TXT
// Where the real fully qualified filepath in the NTFS volume is C:\Temp.TXT

아래 코드와 다양한 변형을 시도했지만 여전히 작동하지 않습니다.Windows는 일반적으로 대소문자를 구분하지 않는다는 것을 알고 있지만 Unix 및 Windows 애플리케이션이므로 파일 경로 대소문자를 고려하는 ClearCase에 이러한 파일 경로를 전달해야 합니다.

public static string GetProperFilePathCapitalization(string filepath)
{
    string result = "";

    try
    {
        result = Path.GetFullPath(filepath);
        DirectoryInfo dir = new DirectoryInfo(Path.GetDirectoryName(result));
        FileInfo[] fi = dir.GetFiles(Path.GetFileName(result));
        if (fi.Length > 0)
        {
            result = fi[0].FullName;
        }
    }
    catch (Exception)
    {
        result = filepath;
    }

    return result;
}
도움이 되었습니까?

해결책

이는 파일과 디렉터리가 모두 존재하고 액세스 가능하다고 가정하는 매우 간단한 구현입니다.

static string GetProperDirectoryCapitalization(DirectoryInfo dirInfo)
{
    DirectoryInfo parentDirInfo = dirInfo.Parent;
    if (null == parentDirInfo)
        return dirInfo.Name;
    return Path.Combine(GetProperDirectoryCapitalization(parentDirInfo),
                        parentDirInfo.GetDirectories(dirInfo.Name)[0].Name);
}

static string GetProperFilePathCapitalization(string filename)
{
    FileInfo fileInfo = new FileInfo(filename);
    DirectoryInfo dirInfo = fileInfo.Directory;
    return Path.Combine(GetProperDirectoryCapitalization(dirInfo),
                        dirInfo.GetFiles(fileInfo.Name)[0].Name);
}

하지만 여기에는 버그가 있습니다.상대 경로는 절대 경로로 변환됩니다.위의 원본 코드도 동일하므로 이 동작을 원한다고 가정합니다.

다른 팁

아래는 내가 테스트한 범위 내에서 잘 작동합니다...유일한 문제는 사용된 API가 Vista에서만 사용할 수 있다는 것입니다.

static void Main(string[] args)
{
    using (FileStream fs = File.OpenRead(@"D:\temp\case\mytest.txt"))
    {
        StringBuilder path = new StringBuilder(512);
        GetFinalPathNameByHandle(fs.SafeFileHandle.DangerousGetHandle(), path, path.Capacity, 0);
        Console.WriteLine(path.ToString());
    }
}

[DllImport("kernel32.dll", SetLastError = true)]
static extern int GetFinalPathNameByHandle(IntPtr handle, [In, Out] StringBuilder path, int bufLen, int flags);

사건을 처리하려는 파일을 검색하고 검색 결과를 반환할 수 있습니다(존재하는 파일의 대소문자를 확인하고 싶으신가요?).이 같은:

public static string GetProperFilePathCapitalization(string filepath) {
   string directoryPath = Path.GetDirectoryName(filepath);
   string[] files = Directory.GetFiles(directoryPath, Path.GetFileName(filepath));
   return files[0];
}

이것이 당신이 찾고 있는 것인가요?

더 효율적인 것이 있지만 다음과 같습니다.

1) 모든 경우에 적용되는 것은 아닙니다.(어떤 파일과 디렉토리가 대소문자를 올바르게 인식하는지, 어떤 파일과 디렉토리는 그렇지 않은지 패턴을 파악하지 못했습니다.)

2) Windows에만 해당됩니다.

static string GetProperFilePathCapitalization1(string filename)
{
    StringBuilder sb = new StringBuilder(260);
    int length = GetLongPathName(filename, sb, sb.Capacity);

    if (length > sb.Capacity)
    {
        sb.Capacity = length;
        length = GetLongPathName(filename, sb, sb.Capacity);
    }

    if (0 == length)
        throw new Win32Exception("GetLongPathName");

    return sb.ToString();
}

[DllImport("kernel32.dll")]
static extern int GetLongPathName(string path, StringBuilder pszPath, int cchPath);

위의 @Ants의 답변은 다음과 같습니다. 전적으로 허용되는 답변으로 크레딧을 받으세요.그러나 나는 그것을 내 목적에 맞게 약간 리팩토링했습니다.이 접근 방식은 FileInfo 및 DirectoryInfo에 대한 확장 메서드로 패키지되어 있으며 수정된 메서드도 반환합니다.

public static DirectoryInfo GetProperCasedDirectoryInfo(this DirectoryInfo dirInfo)
{
    // Inspired by http://stackoverflow.com/a/479198/244342

    if (!dirInfo.Exists)
    {
        // Will not be able to match filesystem
        return dirInfo;
    }

    DirectoryInfo parentDirInfo = dirInfo.Parent;
    if (parentDirInfo == null)
    {
        return dirInfo;
    }
    else
    {
        return parentDirInfo.GetProperCasedDirectoryInfo().GetDirectories(dirInfo.Name)[0];
    }
}

public static FileInfo GetProperCasedFileInfo(this FileInfo fileInfo)
{
    // Inspired by http://stackoverflow.com/a/479198/244342

    if (!fileInfo.Exists)
    {
        // Will not be able to match filesystem
        return fileInfo;
    }

    return fileInfo.Directory.GetProperCasedDirectoryInfo().GetFiles(fileInfo.Name)[0];
}

저는 FileInfo의 대/소문자 불일치 문제 때문에 고민하고 있습니다.견고성을 보장하기 위해 경로를 비교하거나 저장할 때 모두 대문자로 변환합니다.코드의 의도를 명확히 하기 위해 다음과 같은 확장 메서드도 있습니다.

public static string GetPathForKey(this FileInfo File)
{
    return File.FullName.ToUpperInvariant();
}

public static string GetDirectoryForKey(this FileInfo File)
{
    return File.DirectoryName.ToUpperInvariant();
}

시스템이 파일을 찾아주기를 원할 것입니다.나는 정확한 경로를 모르는 척함으로써 이 작업을 수행합니다.시스템을 가지고 있다 찾다:

var fileName = Path.GetFileName(filePath);
var dir = Path.GetDirectoryName(filePath);
var filePaths = Directory.GetFiles(dir, fileName, SearchOption.TopDirectoryOnly);
var caseCorrectedFilePath = filePaths.FirstOrDefault();

따라서 디렉토리에서 검색하여 정확한 파일 이름을 필터링하고 현재 디렉토리로만 검색을 제한합니다(재귀 없음).

이는 대/소문자가 올바른 단일 파일 경로(파일이 있는 경우) 또는 아무것도 포함하지 않는(파일이 없는 경우) 문자열 배열을 반환합니다.

한 가지 경고:이 접근 방식에서는 와일드카드를 허용하고 결과적으로 여러 파일을 찾을 수 있으므로 입력 경로에서 와일드카드를 허용하지 않아야 할 수도 있습니다.

편집하다

드라이브 문자는 여전히 우리가 제공하는 케이스를 따르는 것으로 보입니다.또한 UNC 경로에 대해서도 테스트해야 합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top