2013-04-24 2 views
9

Есть ли способ иметь дело чувствительную Directory.Exists/File.Exists такчувствителен к регистру Directory.Exists/File.Exists

Directory.Exists(folderPath) 

и

Directory.Exists(folderPath.ToLower()) 

возвращают true?

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

+0

MSDN четко отметил это: «Параметр пути не чувствителен к регистру.», См. Http://msdn.microsoft.com/en-us/library/system.io.directory.exists.aspx – David

+6

Я знаю, вот почему я спрашиваю ... – theknut

ответ

5

Поскольку Directory.Exists использует FindFirstFile, который не чувствителен к регистру, нет. Но вы можете PInvoke FindFirstFileEx с additionalFlags параметра на FIND_FIRST_EX_CASE_SENSITIVE

+1

Извините, может быть, вопрос с дампом, но это работает на C#? Все ваши ссылки относятся к C++ * confused * – theknut

+0

Да, это нужно сделать, вы можете использовать P/Invoke для вызова Win32 с C#, читать P/Invoke и затем проверить ссылку на pinvoke.net – Matt

+0

+1. @ theknut, ссылка PInvoke дает вам подробную информацию о том, как сделать ее вызываемой на языках C#/.Net. –

0

Попробуйте эту функцию:

public static bool FileExistsCaseSensitive(string filename) 
{ 
    string name = Path.GetDirectoryName(filename); 

    return name != null 
      && Array.Exists(Directory.GetFiles(name), s => s == Path.GetFullPath(filename)); 
} 

Update:

Как указано в комментариях, это только проверка случаев в имени файла, а не в путь. Это связано с тем, что метод GetFullPath не возвращает исходный путь Windows с исходными случаями, а копирует путь из этого параметра.

Ex:

GetFullPath("c:\TEST\file.txt") -> "c:\TEST\file.txt" 
GetFullPath("c:\test\file.txt") -> "c:\test\file.txt" 

Все методы я пытался работать таким же образом: Fileinfo, DirectoryInfo.

Вот решение, используя метод kernel32.dll: (? BOOL)

[DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
    public static extern int GetLongPathName(
     string path, 
     StringBuilder longPath, 
     int longPathLength 
     ); 

    /// <summary> 
    /// Return true if file exists. Non case sensitive by default. 
    /// </summary> 
    /// <param name="filename"></param> 
    /// <param name="caseSensitive"></param> 
    /// <returns></returns> 
    public static bool FileExists(string filename, bool caseSensitive = false) 
    { 
     if (!File.Exists(filename)) 
     { 
      return false; 
     } 

     if (!caseSensitive) 
     { 
      return true; 
     } 

     //check case 
     StringBuilder longPath = new StringBuilder(255); 
     GetLongPathName(Path.GetFullPath(filename), longPath, longPath.Capacity); 

     string realPath = Path.GetDirectoryName(longPath.ToString()); 
     return Array.Exists(Directory.GetFiles(realPath), s => s == filename); 
    } 
+0

Я пробовал, и он не работает. – LVBen

+0

Он работает здесь: если у вас есть c: \ temp \ TEST.txt, FileExistsCaseSensitive (@ "c: \ temp \ test.txt") вернет false –

+0

Это работает для меня. (проверено на платформе Windows) –

0

Попробуйте эти 2 простые варианты, которые не должны использовать PInvoke и вернуть обнуляемого Boolean. Я не эксперт по теме, поэтому я знаю, что это самый эффективный код, но он работает для меня.

Просто пройдите по пути, и если результат равен null (HasValue = false), совпадение не найдено, если результат является ложным, существует точное совпадение, в противном случае, если true, существует совпадение с разным случаем.

Методы GetFiles, GetDirectories и GetDrives возвращают точный случай, сохраненный в вашей файловой системе, поэтому вы можете использовать метод сравнения с учетом регистра.

NB: для случая, когда путь является точным приводом (например, @ "C: \") Я должен использовать несколько иной подход.

using System.IO; 
class MyFolderFileHelper { 
    public static bool? FileExistsWithDifferentCase(string fileName) 
    { 
     bool? result = null; 
     if (File.Exists(fileName)) 
     { 
      result = false; 
      string directory = Path.GetDirectoryName(fileName); 
      string fileTitle = Path.GetFileName(fileName); 
      string[] files = Directory.GetFiles(directory, fileTitle); 
      if (String.Compare(files[0], fileName, false) != 0) 
       result = true;     
     } 
     return result; 
    } 

    public static bool? DirectoryExistsWithDifferentCase(string directoryName) 
    { 
     bool? result = null; 
     if (Directory.Exists(directoryName)) 
     { 
      result = false; 
      directoryName = directoryName.TrimEnd(Path.DirectorySeparatorChar); 

      int lastPathSeparatorIndex = directoryName.LastIndexOf(Path.DirectorySeparatorChar); 
      if (lastPathSeparatorIndex >= 0) 
      {      
       string baseDirectory = directoryName.Substring(lastPathSeparatorIndex + 1); 
       string parentDirectory = directoryName.Substring(0, lastPathSeparatorIndex); 

       string[] directories = Directory.GetDirectories(parentDirectory, baseDirectory); 
       if (String.Compare(directories[0], directoryName, false) != 0) 
        result = true; 
      } 
      else 
      { 
       //if directory is a drive 
       directoryName += Path.DirectorySeparatorChar.ToString(); 
       DriveInfo[] drives = DriveInfo.GetDrives(); 
       foreach(DriveInfo driveInfo in drives) 
       { 
        if (String.Compare(driveInfo.Name, directoryName, true) == 0) 
        { 
         if (String.Compare(driveInfo.Name, directoryName, false) != 0) 
          result = true; 
         break; 
        } 
       } 

      } 
     } 
     return result; 
    } 
} 
1

На основании решения this question, я написал ниже код, который чувствителен к регистру для всего пути кроме буквы Окна привода:

static void Main(string[] args) 
    { 
     string file1 = @"D:\tESt\Test.txt"; 
     string file2 = @"d:\Test\test.txt"; 
     string file3 = @"d:\test\notexists.txt"; 

     bool exists1 = Case_Sensitive_File_Exists(file1); 
     bool exists2 = Case_Sensitive_File_Exists(file2); 
     bool exists3 = Case_Sensitive_File_Exists(file3); 

     Console.WriteLine("\n\nPress any key..."); 
     Console.ReadKey(); 
    } 

    static bool Case_Sensitive_File_Exists(string filepath) 
    { 
     string physicalPath = GetWindowsPhysicalPath(filepath); 
     if (physicalPath == null) return false; 
     if (filepath != physicalPath) return false; 
     else return true; 
    } 

я скопировал код для GetWindowsPhysicalPath(string path) из the question

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
    static extern uint GetLongPathName(string ShortPath, StringBuilder sb, int buffer); 

    [DllImport("kernel32.dll")] 
    static extern uint GetShortPathName(string longpath, StringBuilder sb, int buffer); 

    protected static string GetWindowsPhysicalPath(string path) 
    { 
     StringBuilder builder = new StringBuilder(255); 

     // names with long extension can cause the short name to be actually larger than 
     // the long name. 
     GetShortPathName(path, builder, builder.Capacity); 

     path = builder.ToString(); 

     uint result = GetLongPathName(path, builder, builder.Capacity); 

     if (result > 0 && result < builder.Capacity) 
     { 
      //Success retrieved long file name 
      builder[0] = char.ToLower(builder[0]); 
      return builder.ToString(0, (int)result); 
     } 

     if (result > 0) 
     { 
      //Need more capacity in the buffer 
      //specified in the result variable 
      builder = new StringBuilder((int)result); 
      result = GetLongPathName(path, builder, builder.Capacity); 
      builder[0] = char.ToLower(builder[0]); 
      return builder.ToString(0, (int)result); 
     } 

     return null; 
    } 

Примечание Единственная проблема, с которой я столкнулся с этой функцией, - это то, что буква диска всегда находится в нижнем регистре. Пример: Физический путь на окнах: D:\Test\test.txt, функция GetWindowsPhysicalPath(string path) возвращает d:\Test\test.txt

+1

Id рекомендует создать поле для '[ThreadStatic] StringBuilder _builder = new StringBuilder (255);' и тем самым избежать добавления распределения для каждого вызова. На самом деле .. устранение ассигнований будет немного большим изменением, чем просто ... hm. – James

0

Если (относительный или абсолютный) путь вашего файла:

string AssetPath = "..."; 

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

if(File.Exists(AssetPath) && Path.GetFullPath(AssetPath) == Directory.GetFiles(Path.GetDirectoryName(Path.GetFullPath(AssetPath)), Path.GetFileName(Path.GetFullPath(AssetPath))).Single()) 
{ 
} 

Наслаждайтесь!

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