如何使用Directory.EnumerateFiles排除隐藏文件和系统文件
How to use Directory.EnumerateFiles excluding hidden and system files
我正在枚举目录中的所有文件,以便稍后处理它们。我想排除隐藏文件和系统文件。
这是我目前拥有的:
IEnumerable<IGrouping<string, string>> files;
files = Directory.EnumerateFiles(sourcePath, "*", SearchOption.AllDirectories)
.Where(f => (new FileInfo(f).Attributes & FileAttributes.Hidden & FileAttributes.System) == 0)
.GroupBy(Path.GetDirectoryName);
但是,如果我查看结果,我仍然隐藏并包含系统文件:
foreach (var folder in files)
{
foreach (var file in folder)
{
// value for file here still shows hidden/system file paths
}
}
我发现 this question 中有一个来自 Jerome 的类似示例,但我什至无法编译它。
我做错了什么?
.Where(f => (new FileInfo(f).Attributes & FileAttributes.Hidden & FileAttributes.System) == 0)
由于FileAttributes
值是标志,它们在位级别上是分离的,因此您可以将它们适当地组合起来。因此,FileAttributes.Hidden & FileAttributes.System
将永远是 0
。因此,您实际上是在检查以下内容:
(new FileInfo(f).Attributes & 0) == 0
这将永远是正确的,因为您要删除 & 0
部分的任何值。
您要检查的是文件是否没有这些标志,或者换句话说,如果没有共同的标志与两者的组合:
.Where(f => (new FileInfo(f).Attributes & (FileAttributes.Hidden | FileAttributes.System)) == 0)
您也可以使用 Enum.HasFlag
使它更容易理解:
.Where(f => !new FileInfo(f).Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System))
您可以使用 FileSystemInfo.Attributes.HasFlag
:
DirectoryInfo dir = new DirectoryInfo( sourcePath );
var files = dir.EnumerateFiles("*", SearchOption.AllDirectories)
.Where(f => !f.Attributes.HasFlag(FileAttributes.Hidden) && !f.Attributes.HasFlag(FileAttributes.System))
.GroupBy(f => f.DirectoryName);
您可以使用 DirectoryInfo 和 FileInfo 大大简化您的代码,例如:
var mask= FileAttributes.Hidden | FileAttributes.System;
var di=new DirectoryInfo(sourcePath);
var files=di.EnumerateFiles("*", SearchOption.AllDirectories)
.Where(fi=>(fi.Attributes & mask) == 0)
.GroupBy(fi=>fi.DirectoryName);
您的原始代码试图在没有公共位的标志之间执行按位与运算,因此返回 0。结果,与 Attributes
的按位与运算也返回 0。
您要检查的掩码是系统 或 隐藏的,即 FileAttributes.Hidden | FileAttributes.System
。提前计算只会使代码更清晰
我正在枚举目录中的所有文件,以便稍后处理它们。我想排除隐藏文件和系统文件。
这是我目前拥有的:
IEnumerable<IGrouping<string, string>> files;
files = Directory.EnumerateFiles(sourcePath, "*", SearchOption.AllDirectories)
.Where(f => (new FileInfo(f).Attributes & FileAttributes.Hidden & FileAttributes.System) == 0)
.GroupBy(Path.GetDirectoryName);
但是,如果我查看结果,我仍然隐藏并包含系统文件:
foreach (var folder in files)
{
foreach (var file in folder)
{
// value for file here still shows hidden/system file paths
}
}
我发现 this question 中有一个来自 Jerome 的类似示例,但我什至无法编译它。
我做错了什么?
.Where(f => (new FileInfo(f).Attributes & FileAttributes.Hidden & FileAttributes.System) == 0)
由于FileAttributes
值是标志,它们在位级别上是分离的,因此您可以将它们适当地组合起来。因此,FileAttributes.Hidden & FileAttributes.System
将永远是 0
。因此,您实际上是在检查以下内容:
(new FileInfo(f).Attributes & 0) == 0
这将永远是正确的,因为您要删除 & 0
部分的任何值。
您要检查的是文件是否没有这些标志,或者换句话说,如果没有共同的标志与两者的组合:
.Where(f => (new FileInfo(f).Attributes & (FileAttributes.Hidden | FileAttributes.System)) == 0)
您也可以使用 Enum.HasFlag
使它更容易理解:
.Where(f => !new FileInfo(f).Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System))
您可以使用 FileSystemInfo.Attributes.HasFlag
:
DirectoryInfo dir = new DirectoryInfo( sourcePath );
var files = dir.EnumerateFiles("*", SearchOption.AllDirectories)
.Where(f => !f.Attributes.HasFlag(FileAttributes.Hidden) && !f.Attributes.HasFlag(FileAttributes.System))
.GroupBy(f => f.DirectoryName);
您可以使用 DirectoryInfo 和 FileInfo 大大简化您的代码,例如:
var mask= FileAttributes.Hidden | FileAttributes.System;
var di=new DirectoryInfo(sourcePath);
var files=di.EnumerateFiles("*", SearchOption.AllDirectories)
.Where(fi=>(fi.Attributes & mask) == 0)
.GroupBy(fi=>fi.DirectoryName);
您的原始代码试图在没有公共位的标志之间执行按位与运算,因此返回 0。结果,与 Attributes
的按位与运算也返回 0。
您要检查的掩码是系统 或 隐藏的,即 FileAttributes.Hidden | FileAttributes.System
。提前计算只会使代码更清晰