Изменение пути к файлу C #
-
20-08-2019 - |
Вопрос
Я пытаюсь написать статическую функцию-член на 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;
}
Решение
Это довольно простая реализация, которая предполагает, что все файлы и каталоги существуют и доступны:
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-путей.