다음 코드가 있습니다.
List<string> result = new List<string>();
foreach (string file in Directory.EnumerateFiles(path,"*.*",
SearchOption.AllDirectories)
.Where(s => s.EndsWith(".mp3") || s.EndsWith(".wma")))
{
result.Add(file);
}
잘 작동하고 필요한 것을 수행합니다. 한 가지 작은 것을 제외하고. 여러 확장을 필터링하는 더 좋은 방법을 찾고 싶습니다. 다음과 같은 필터와 함께 문자열 배열을 사용하고 싶습니다.
string[] extensions = { "*.mp3", "*.wma", "*.mp4", "*.wav" };
NET Framework 4.0 / LINQ를 사용하여이 작업을 수행하는 가장 효율적인 방법은 무엇입니까? 어떤 제안?
가끔 프로그래머가되어 주셔서 감사합니다 🙂
답변
이 문제를 해결하기 위해 올해 초에 블로그 에 올린 몇 가지 도우미 방법을 만들었습니다 .
한 버전은 정규식 패턴 \.mp3|\.mp4
을 사용하고 다른 버전은 문자열 목록을 사용하여 병렬로 실행됩니다.
public static class MyDirectory
{ // Regex version
public static IEnumerable<string> GetFiles(string path,
string searchPatternExpression = "",
SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
Regex reSearchPattern = new Regex(searchPatternExpression, RegexOptions.IgnoreCase);
return Directory.EnumerateFiles(path, "*", searchOption)
.Where(file =>
reSearchPattern.IsMatch(Path.GetExtension(file)));
}
// Takes same patterns, and executes in parallel
public static IEnumerable<string> GetFiles(string path,
string[] searchPatterns,
SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
return searchPatterns.AsParallel()
.SelectMany(searchPattern =>
Directory.EnumerateFiles(path, searchPattern, searchOption));
}
}
답변
LINQ 컨텍스트에서 제외되어 파일이 확장명 목록과 일치하는지 확인하는 방법이 있습니다. System.IO.Path.GetExtension()
여기에서보다 나은 선택 String.EndsWith()
입니다. 다중은 ||
교체 할 수 있습니다 .Contains()
또는 .IndexOf()
컬렉션에 따라 달라집니다.
var extensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{ ".mp3", ".wma", ".mp4", ".wav" };
... s => extensions.Contains(Path.GetExtension(s))
답변
가장 우아한 접근 방식은 다음과 같습니다.
var directory = new DirectoryInfo(path);
var masks = new[] { "*.mp3", "*.wav" };
var files = masks.SelectMany(directory.EnumerateFiles);
그러나 가장 효율적이지 않을 수 있습니다.
답변
string path = "C:\\";
var result = new List<string>();
string[] extensions = { ".mp3", ".wma", ".mp4", ".wav" };
foreach (string file in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories)
.Where(s => extensions.Any(ext => ext == Path.GetExtension(s))))
{
result.Add(file);
Console.WriteLine(file);
}
답변
주석에서 언급했듯이 Mikael Svenson의 도우미 메서드는 아주 작은 솔루션이지만 일회성 프로젝트를 위해 서둘러 다시 작업을 시도한다면 Linq 확장 .Union ()을 고려하십시오 . 이렇게하면 두 개의 열거 가능한 시퀀스를 결합 할 수 있습니다. 귀하의 경우 코드는 다음과 같습니다.
List<string> result = Directory.EnumerateFiles(path,"*.mp3", SearchOption.AllDirectories)
.Union(Directory.EnumerateFiles(path, ".wma", SearchOption.AllDirectories)).ToList();
이렇게하면 결과 목록이 모두 한 줄로 생성되고 채워집니다.
답변
나는 이것이 오래된 게시물이라는 것을 알고 있지만 사람들이 사용하고 싶은 해결책을 생각해 냈습니다.
private IEnumerable<FileInfo> FindFiles()
{
DirectoryInfo sourceDirectory = new DirectoryInfo(@"C:\temp\mydirectory");
string foldersFilter = "*bin*,*obj*";
string fileTypesFilter = "*.mp3,*.wma,*.mp4,*.wav";
// filter by folder name and extension
IEnumerable<DirectoryInfo> directories = foldersFilter.Split(',').SelectMany(pattern => sourceDirectory.EnumerateDirectories(pattern, SearchOption.AllDirectories));
List<FileInfo> files = new List<FileInfo>();
files.AddRange(directories.SelectMany(dir => fileTypesFilter.Split(',').SelectMany(pattern => dir.EnumerateFiles(pattern, SearchOption.AllDirectories))));
// Pick up root files
files.AddRange(fileTypesFilter.Split(',').SelectMany(pattern => sourceDirectory.EnumerateFiles(fileTypesFilter, SearchOption.TopDirectoryOnly)));
// filter just by extension
IEnumerable<FileInfo> files2 = fileTypesFilter.Split(',').SelectMany(pattern => sourceDirectory.EnumerateFiles(pattern, SearchOption.AllDirectories));
}
답변
GUI 열기 대화 상자와 동일한 파일 확장자 목록 문자열을 사용하는 필터링의 경우 예 :
".exe,.pdb".Split(',', ';', '|').SelectMany(_ => Directory.EnumerateFiles(".", "*" + _, searchOptions)
포장 :
public static IEnumerable<string> EnumerateFilesFilter(string path, string filesFilter, SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
return filesFilter.Split(',', ';', '|').SelectMany(_ => Directory.EnumerateFiles(path, "*" + _, searchOption));
}