C # Filepath Recasing - PullRequest
       28

C # Filepath Recasing

21 голосов
/ 26 января 2009

Я пытаюсь написать статическую функцию-член на 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 вообще не учитывает регистр, но мне нужно передать эти пути к файлам в ClearCase, который учитывает регистр путей к файлам, поскольку это приложение для Unix и Windows.

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;
}

Ответы [ 6 ]

22 голосов
/ 26 января 2009

Это довольно простая реализация, которая предполагает, что файл и каталоги все существуют и доступны:

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);
}

Однако в этом есть ошибка: относительные пути преобразуются в абсолютные. Ваш оригинальный код выше сделал то же самое, поэтому я предполагаю, что вы действительно хотите такое поведение.

3 голосов
/ 28 января 2009

Приведенное ниже прекрасно работает в той степени, в которой я тестировал ... единственное преимущество в том, что используемый 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);
1 голос
/ 08 августа 2012

Ответ @Ats выше должен абсолютно получить кредит в качестве принятого ответа. Тем не менее, я немного изменил его для своих целей. Подход упакован как методы расширения для 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();
}
1 голос
/ 28 января 2009

У меня есть что-то более эффективное, но:

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);
1 голос
/ 26 января 2009

Вы можете найти файл, в котором вы хотите получить дело, и вернуть результаты вашего поиска (вы хотите проверить регистр файла, который существует, верно?). Примерно так:

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

Это то, что вы ищете?

0 голосов
/ 04 ноября 2015

Вы хотите, чтобы система нашла файл для вас. Я делаю это, притворяясь, что не знаю точного пути, то есть система search :

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

Таким образом, мы ищем в каталоге, фильтруем по точному имени файла и ограничиваем поиск только текущим каталогом (без рекурсии).

Возвращает строковый массив, содержащий либо единственный путь к файлу с правильным регистром (если файл существует), либо ничего (если файл не существует).

Одно предупреждение: вам может потребоваться запретить использование подстановочных знаков в пути ввода, поскольку этот подход принимает их и в результате может найти несколько файлов.

Редактировать

Кажется, что буква диска все еще следует за предоставленным нами регистром. Кроме того, это необходимо проверить на пути UNC.

...