问题
Is there a way to have a case sensitive Directory.Exists
/ File.Exists
since
Directory.Exists(folderPath)
and
Directory.Exists(folderPath.ToLower())
both return true
?
Most of the time it doesn't matter but I'm using a macro which seems not to work if the path doesn't match cases 100%.
回答1:
Since Directory.Exists uses FindFirstFile which is not case-sensitive, no. But you can PInvoke FindFirstFileEx with an additionalFlags parameter set to FIND_FIRST_EX_CASE_SENSITIVE
回答2:
Based on the solution of this question, I wrote the code below which is case sensitive for the whole path except the Windows Drive letter:
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;
}
I copied the code for GetWindowsPhysicalPath(string path)
from 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;
}
Note the only problem I found with this function is, the drive letter seems to be always in lowercase. Example: The physical path on Windows is: D:\Test\test.txt
, the GetWindowsPhysicalPath(string path)
function returns d:\Test\test.txt
回答3:
Try this function:
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:
As stated in comments, this only check cases in filename, not in the path. This is because GetFullPath method doesn't return the Windows original path with original cases, but a copy of the path from the parameter.
Ex:
GetFullPath("c:\TEST\file.txt") -> "c:\TEST\file.txt"
GetFullPath("c:\test\file.txt") -> "c:\test\file.txt"
All methods I tried work the same way: Fileinfo, DirectoryInfo.
Here is a solution using a kernel32.dll method:
[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);
}
回答4:
Try these 2 simpler options that do not need to use PInvoke and return a nullable Boolean (bool?). I am not a subject expert so I do know if this is the most efficient code but it works for me.
Simply pass in a path and if the result is null (HasValue = false) no match is found, if the result is false there is an exact match, otherwise if true there is a match with a difference case.
The methods GetFiles, GetDirectories and GetDrives all return the exact case as saved on your file system so you can use a case sensitive compare method.
NB: for the case where the path is an exact drive (e.g. @"C:\") I have to use a slightly different approach.
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;
}
}
回答5:
If the (relative or absolute) path of your file is:
string AssetPath = "...";
The following ensures that the file both exists and has the correct casing:
if(File.Exists(AssetPath) && Path.GetFullPath(AssetPath) == Directory.GetFiles(Path.GetDirectoryName(Path.GetFullPath(AssetPath)), Path.GetFileName(Path.GetFullPath(AssetPath))).Single())
{
}
Enjoy!
来源:https://stackoverflow.com/questions/16183788/case-sensitive-directory-exists-file-exists