c# - Directory.EnumerateFiles 搜索模式不适用于文件共享
问题描述
根据Directory.EnumerateFiles 的 Microsoft Docs 站点,搜索模式参数将匹配以指定模式开头的任何扩展名,当它正好是 3 个字符时。但是,这不适用于文件共享,仅适用于本地驱动器。
对于\\share\folder\
包含名为 的单个文件的目录file.xlsx
,第一个代码片段不会返回它:
public static List<string> GetAllFilesFromDirectory(string directory) =>
new[] { "*.csv", "*.xls", "*.txt" }.SelectMany(ext => Directory.EnumerateFiles(directory, ext)).ToList();
但是,如果我添加*.xlsx
模式,它会返回它:
public static List<string> GetAllFilesFromDirectory(string directory) =>
new[] { "*.csv", "*.xls", "*.xlsx", "*.txt" }.SelectMany(ext => Directory.EnumerateFiles(directory, ext)).ToList();
我还用目录中的相同文件对此进行了测试C:\temp
,发现它以两种方式返回。
这是在 .NET Framework 4.7.2 控制台应用程序中运行的。
我在搜索模式中遗漏了什么吗?或者这不适用于文件共享与本地驱动器相同的方式?这是可以预期的吗?
解决方案
你一定是最倒霉的人,碰到了这个bug。我可以确认它的行为符合您的观察,并且在互联网上的任何地方都找不到对此的任何引用。
因此,我跟踪了 .NET 源代码以了解其Directory.EnumerateFiles
工作原理,并且 - 在内心深处 - 最终遇到了调用和FindFirstFile
后续FindNextFile
调用。这些是直接从内核中调用的,所以你不能得到比这更低的值。
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
那得测试一下。你猜怎么了?它在本地目录中捕获 XLSX 文件,但不在网络共享中。
该函数的文档也没有提到这种行为。是的。您刚刚遇到了一个未记录的“功能”:)
编辑:这变得更好了。看起来在.NET Core(从 2.0 一直到 .NET 5)这种行为不再存在。这次他们实际上编写了自己的模式匹配器。*.xls
不会在任何本地或其他文件夹中捕获 XLSX。然而他们的文件仍然说它应该。
2021 年编辑:该文档现已更新,其中包含有关 .NET Framework 怪癖的评论。
这是我的通话测试代码FindFirstFile
:
public class Program
{
public static void Main(string[] args)
{
// Ensure these test folders only contain ONE file.
// Name the file "Test.xlsx"
Test(@"C:\Temp\*.xls"); // Finds the xlsx file just fine
Test(@"\\Server\Temp\*.xls"); // But not here!
}
public static void Test(string fileName)
{
Win32Native.WIN32_FIND_DATA data;
var hnd = Win32Native.FindFirstFile(fileName, out data);
if (hnd == Win32Native.InvalidPtr)
Debug.WriteLine("Not found!!");
else
Debug.WriteLine("Found: " + data.cFileName);
}
}
/** Windows native Pinvoke **/
public class Win32Native
{
public static IntPtr InvalidPtr = new IntPtr(-1);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public 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;
}
}
推荐阅读
- javascript - 了解 JavaScript 中的对象创建
- asp.net - Asp.net Core Web API 中的自定义返回
- java - 多对多实体上的 JPA WHERE 子句
- postgresql - 刷新postgres物化视图的表现
- javascript - Javascript 创建带有图片和歌曲的视频
- go - 我正在尝试使用 mux 和 httptest 在 Golang 中测试 REST Api 客户端
- iis - 在哪个区域添加 CNAME 条目?
- linux - 让 rsync 在复制之前对文件进行快照
- android - 构建 JavaScript 包失败。无法解析“expo-barcode-scanner”
- python - Selenium GDPR NoSuchElementException