2009-07-31 5 views
17

Вот проблема, у меня есть куча каталогов, какНормализация имена каталогов в C#

S: \ ПРИВЕТ \ HI
S: \ hello2 \ Привет \ HElloAgain

О файле система он показывает эти каталоги как

S: \ привет \ Привет
S: \ hello2 \ Hi \ helloAgain

Есть ли какая-либо функция в C#, которая даст мне то, что имя файловой системы каталога с соответствующим корпусом?

+0

Там в нет никакой функции для этого, и попытка нормализовать строки, такие как «HElloAgain», на «helloAgain» будет проблемой, так как даже Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase («HElloAgain») вернет «Helloagain». –

+0

@Agent, DirectoryInfo. GetDirectories() возвращает папки в случае файловой системы. – Kevin

+1

Принято, ничего себе, я понятия не имел, что новые ответы были здесь. Спасибо и Iceman и Bertu за помощь в решении этого вопроса. – Tom

ответ

8

string FileSystemCasing = new System.IO.DirectoryInfo("H:\...").FullName;

EDIT:

Как Iceman указал, FullName возвращает правильный корпус, только если DirectoryInfo (или вообще FileSystemInfo) исходит от вызова к GetDirectories (или GetFileSystemInfos) методом.

Теперь я отправляю протестированное и оптимизированное по производительности решение. Он хорошо работает как по каталогам, так и по файловым путям и имеет некоторую отказоустойчивость на входной строке. Он оптимизирован для «преобразования» одиночных путей (не всей файловой системы) и быстрее, чем получение всего дерева файловой системы. Конечно, если у вас есть перенормировать все дерево файловой системы, вы можете предпочесть решение Iceman, но я тестировал на 10000 итераций по дорожкам со средним уровнем глубины, и это занимает всего несколько секунд;)

private string GetFileSystemCasing(string path) 
    { 
     if (Path.IsPathRooted(path)) 
     { 
      path = path.TrimEnd(Path.DirectorySeparatorChar); // if you type c:\foo\ instead of c:\foo 
      try 
      { 
       string name = Path.GetFileName(path); 
       if (name == "") return path.ToUpper() + Path.DirectorySeparatorChar; // root reached 

       string parent = Path.GetDirectoryName(path); // retrieving parent of element to be corrected 

       parent = GetFileSystemCasing(parent); //to get correct casing on the entire string, and not only on the last element 

       DirectoryInfo diParent = new DirectoryInfo(parent); 
       FileSystemInfo[] fsiChildren = diParent.GetFileSystemInfos(name); 
       FileSystemInfo fsiChild = fsiChildren.First(); 
       return fsiChild.FullName; // coming from GetFileSystemImfos() this has the correct case 
      } 
      catch (Exception ex) { Trace.TraceError(ex.Message); throw new ArgumentException("Invalid path"); } 
      return ""; 
     } 
     else throw new ArgumentException("Absolute path needed, not relative"); 
    } 
+1

Это не работает. Он возвращает тот же случай, что и в конструкторе DirectoryInfo, и игнорирует фактический регистр, хранящийся в файловой системе, но это случай файловой системы, который он хочет. – Kevin

+0

Вы правы. Я отредактировал, чтобы представить полный рабочий пример. – BertuPG

+1

Прошу прощения. Ваш первый комментарий казался более враждебным, чем вы, вероятно, имели в виду, и я должен был отпустить его, вместо того, чтобы начинать аргумент. Я действительно должен оставаться в Интернете, когда я сердитый. Разделение пути и получение случая каждой части - действительно хорошая идея, и это делает разницу между болезненно медленными и полезными. Я не могу выдвинуть ваш ответ, если вы его не отредактируете, но это не помешало мне отработать некоторые из ваших других ответов. Извините за то, что я был рывком - я должен вам выпить, если вы когда-нибудь в Денвере. – Kevin

-1

Это следует сделать это:

System.IO.Directory.GetFiles("..."); 
+0

Я не вижу, что вы пытаетесь сказать/подразумеваете Это бросает «Не могу найти часть пути "..." ". – binki

+0

@binki Это просто обычный английский. Замените «...» на любую папку, которую вы действительно хотели найти. –

+0

Тогда я подозреваю, что вы неправильно поняли вопрос. Когда я делаю 'Directory.GetFiles (@" \ USERS \ OHNOB \ HELLO ")', я получаю '{" \ USERS \ OHNOB \ HELLO \ Hi "}' вместо '{" \ Users \ ohnob \ hello \ Hi " } '. Я вполне уверен, что вопрос заключается в том, как получить последний. – binki

-3

 
     static void Main(string[] args) 
     { 
     string[] paths = new string[] { "S:\hello\Hi", "S:\hello2\Hi\helloAgain" }; 
     foreach(string aPath in paths) 
     { 
      string normalizedPath = NormalizePath(aPath); 
      Console.WriteLine("Previous: '{0}', Normalized: '{1}'", aPath, normalizedPath); 
     } 
     Console.Write("\n\n\nPress any key..."); 
     Console.Read(); 
     }

public static string NormalizePath(string path) 
    { 
    StringBuilder sb = new StringBuilder(path); 
    string[] paths = path.Split('\\'); 
    foreach(string folderName in paths) 
    { 
     string normalizedFolderName = ToProperCase(folderName); 
     sb.Replace(folderName, normalizedFolderName); 
    } 
    return sb.ToString(); 
    } 

    /// <summary> 
    /// Converts a string to first character upper and rest lower (Camel Case). 
    /// </summary> 
    /// <param name="stringValue"></param> 
    /// <returns></returns> 
    public static string ToProperCase(string stringValue) 
    { 
    if(string.IsNullOrEmpty(stringValue)) 
     return stringValue; 

    return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(stringValue.ToLower()); 
    } 

+2

Он просит обложку, хранящуюся в файловой системе, не обязательно TitleCasing. – Kevin

4

Вот основной и относительно быстрое решение, продолжайте читать ниже некоторого комментария:

private static string GetCase(string path) 
{  
    DirectoryInfo dir = new DirectoryInfo(path); 
    if (dir.Exists) 
    { 
    string[] folders = dir.FullName.Split(Path.DirectorySeparatorChar); 
    dir = dir.Root; 

    foreach (var f in folders.Skip(1)) 
    {   
     dir = dir.GetDirectories(f).First(); 
    } 

    return dir.FullName; 
    } 
    else 
    { 
    return path; 
    } 
} 

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

Мой первоначальный ответ основывался на получении корпуса для каждой папки на диске, и он работал, но был медленным. Я придумал небольшое улучшение, которое сохранил результаты, но оно было слишком медленным для повседневного использования. Вы можете просмотреть историю изменений для этого комментария, если вам нужно сделать это для каждой вещи на диске, и даже тогда есть, вероятно, способы ускорить этот код. Это было «вот как вы можете это сделать», а не «вот отличный способ сделать это».

Берта, в своем ответе, пришел с идеей разделения пути на его составные части и получить часть корпуса по частям, что не приводит к огромному росту в скорости, так как вы больше не проверять все как в моем первоначальном ответе. Берту также обобщил свое решение как для файлов, так и для каталогов. В моих тестах код, вышедший выше (который использует идею Bertu «Разделить путь и сделать это по частям», но подходит к ней итеративно, а не рекурсивно) работает примерно через половину времени кода Bertu. Я не уверен, что это потому, что его метод также обрабатывает файлы, потому что его использование рекурсии приводит к дополнительным накладным расходам или потому, что он заканчивает вызов Path.GetFileName(path) и Path.GetDirectoryName(path) на каждой итерации. В зависимости от ваших конкретных потребностей какая-то комбинация его ответа и моей проблемы, скорее всего, решит вашу проблему, а также возможно на C#.

В этой заметке я должен упомянуть, что есть some limitations для .Net-обработки имен файлов, и поскольку для этого в .Net требуется создание большого количества объектов DirectoryInfo, вы можете рассмотреть неуправляемый код, если это ваше узкое место.

+0

это работает, но он БОЛЬШО медленно, так как он выполняет полную проверку системы для каталога поиска, и у меня есть более 100 каталогов для нормализации – Tom

+0

@Tom, см. Мое обновление. Сначала я должен был подумать о нескольких каталогах. – Kevin

+0

@Tom: см. Править в MY post! ;) – BertuPG

Смежные вопросы