Windows环境下C#如何读取仅大小写不同的文件?
在Windows系统中用C#读取区分大小写的文件/路径
刚好之前处理过类似的问题,Windows下默认不区分大小写的文件系统确实会给这类仓库操作添不少麻烦,下面给你两种实用的C#解决方案,分别适配不同的.NET版本:
先划个重点:Windows NTFS文件系统**默认是「不区分大小写但保留大小写」**的,普通的.NET文件API(比如File.Exists、Directory.GetFiles)会自动忽略大小写匹配,所以要精准识别仅大小写不同的文件,得用专门的手段。
方法一:用.NET 5+的EnumerationOptions(首推)
从.NET 5开始,官方终于提供了原生的大小写敏感枚举选项,不用再折腾原生API了,代码简洁又可靠:
using System.IO; // 替换成你的仓库路径 var repoPath = @"C:\YourLocalRepo"; var caseSensitiveOptions = new EnumerationOptions { IgnoreCase = false, // 关键:关闭忽略大小写,开启精准匹配 RecurseSubdirectories = true // 如果需要递归遍历子目录就打开 }; // 枚举目录下所有区分大小写的文件 foreach (var filePath in Directory.EnumerateFiles(repoPath, "*", caseSensitiveOptions)) { Console.WriteLine(filePath); } // 精准检查某个大小写的文件是否存在 bool hasUpperCaseFile = File.Exists(Path.Combine(repoPath, "File.txt"), caseSensitiveOptions); bool hasLowerCaseFile = File.Exists(Path.Combine(repoPath, "file.txt"), caseSensitiveOptions);
方法二:P/Invoke调用Win32原生函数(兼容旧版.NET)
如果你还在维护.NET Framework或.NET Core 3.1及更早版本的项目,那就得直接调用Windows原生API了——毕竟旧版.NET没提供直接的大小写敏感支持。
示例1:枚举区分大小写的文件
using System; using System.Runtime.InteropServices; using System.IO; public static class CaseSensitiveFileUtils { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct WIN32_FIND_DATA { public uint dwFileAttributes; public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime; public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime; public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; public uint dwReserved0; public uint dwReserved1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName; } [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr FindFirstFileW(string lpFileName, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern bool FindNextFileW(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool FindClose(IntPtr hFindFile); public static void ListCaseSensitiveFiles(string directoryPath) { var searchPattern = Path.Combine(directoryPath, "*"); IntPtr searchHandle = FindFirstFileW(searchPattern, out WIN32_FIND_DATA fileData); if (searchHandle == IntPtr.Zero) { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } try { do { // 跳过当前目录和父目录的占位符 if (fileData.cFileName != "." && fileData.cFileName != "..") { var fullPath = Path.Combine(directoryPath, fileData.cFileName); Console.WriteLine(fullPath); } } while (FindNextFileW(searchHandle, out fileData)); } finally { FindClose(searchHandle); } } } // 使用方式 CaseSensitiveFileUtils.ListCaseSensitiveFiles(@"C:\YourLocalRepo");
示例2:精准打开特定大小写的文件
如果要直接读取某个指定大小写的文件(比如只打开File.txt而不是file.txt),可以用CreateFileW:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr CreateFileW( string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile); private const uint GENERIC_READ = 0x80000000; private const uint OPEN_EXISTING = 3; public static FileStream OpenExactCaseFile(string filePath) { IntPtr fileHandle = CreateFileW( filePath, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); if (fileHandle == (IntPtr)(-1)) { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } return new FileStream(fileHandle, FileAccess.Read); } // 使用方式 using (var stream = OpenExactCaseFile(@"C:\YourLocalRepo\File.txt")) using (var reader = new StreamReader(stream)) { string content = reader.ReadToEnd(); Console.WriteLine(content); }
额外提醒
- 如果你是用Git管理仓库,记得把
core.ignorecase设为false,不然Git可能会自动转换文件名大小写,导致本地文件系统的大小写混乱:执行git config core.ignorecase false即可。 - 即使你用代码能区分这些文件,Windows资源管理器等系统工具还是会默认把它们当成同一个文件,操作时一定要小心,避免误删或覆盖。
内容的提问来源于stack exchange,提问作者KroegerBa
相关产品推荐
相关产品推荐

