Nhiều phần mở rộng tệp tìm kiếm Mô hình cho System.IO.Directory.GetFiles


140

Cú pháp để thiết lập nhiều phần mở rộng tệp như searchPatterntrên là Directory.GetFiles()gì? Ví dụ: lọc các tệp có phần mở rộng .aspx.ascx .

// TODO: Set the string 'searchPattern' to only get files with
// the extension '.aspx' and '.ascx'.
var filteredFiles = Directory.GetFiles(path, searchPattern);

Cập nhật : LINQ không phải là một tùy chọn , nó phải được searchPatterntruyền vào GetFiles, như được chỉ định trong câu hỏi.


Tôi không nghĩ là có. Liệt kê tất cả các tệp và sau đó lọc thủ công hoặc thực hiện kết hợp trên nhiều người tìm kiếm. Nhưng tôi khá chắc chắn rằng tôi đã thấy câu hỏi chính xác này trên SO trước đây.
CodeInChaos


Đã hỏi và trả lời trước đây tại đây: stackoverflow.com/questions/163162/ Kẻ
David

Câu trả lời:


41

Tôi tin rằng không có giải pháp "ngoài luồng", đó là một hạn chế của phương thức Directory.GetFiles.

Thật dễ dàng để viết phương pháp của riêng bạn, đây là một ví dụ .

Mã có thể là:

/// <summary>
/// Returns file names from given folder that comply to given filters
/// </summary>
/// <param name="SourceFolder">Folder with files to retrieve</param>
/// <param name="Filter">Multiple file filters separated by | character</param>
/// <param name="searchOption">File.IO.SearchOption, 
/// could be AllDirectories or TopDirectoryOnly</param>
/// <returns>Array of FileInfo objects that presents collection of file names that 
/// meet given filter</returns>
public string[] getFiles(string SourceFolder, string Filter, 
 System.IO.SearchOption searchOption)
{
 // ArrayList will hold all file names
ArrayList alFiles = new ArrayList();

 // Create an array of filter string
 string[] MultipleFilters = Filter.Split('|');

 // for each filter find mathing file names
 foreach (string FileFilter in MultipleFilters)
 {
  // add found file names to array list
  alFiles.AddRange(Directory.GetFiles(SourceFolder, FileFilter, searchOption));
 }

 // returns string array of relevant file names
 return (string[])alFiles.ToArray(typeof(string));
}

7
Đây là một cách rất không đủ để làm điều đó, vì bạn sẽ lặp toàn bộ thư mục cho mỗi bộ lọc. Thay vào đó, bạn nên kiểm tra từng tệp nếu nó có bộ lọc sau đó thêm vào để làm danh sách. Bạn có thể sử dụng câu trả lời được giải thích trong chuỗi này: stackoverflow.com/questions/3754118/ trên
ot0

190
var filteredFiles = Directory
    .GetFiles(path, "*.*")
    .Where(file => file.ToLower().EndsWith("aspx") || file.ToLower().EndsWith("ascx"))
    .ToList();

Chỉnh sửa 2014-07-23

Bạn có thể làm điều này trong .NET 4.5 để liệt kê nhanh hơn:

var filteredFiles = Directory
    .EnumerateFiles(path) //<--- .NET 4.5
    .Where(file => file.ToLower().EndsWith("aspx") || file.ToLower().EndsWith("ascx"))
    .ToList();

Directory.Enum CảFiles trong MSDN


5
@Mario Vernari: GetFilestrả lại string[].
jgauffin

4
Bạn phải xóa * khỏi đối số EndsWith (), nó không thực hiện khớp ký tự đại diện.
Hans Passant

3
nếu so sánh các phần mở rộng của tệp, nó sẽ trả về kết quả khớp chính xác như '.Where (file => new FileInfo (tệp) .Extension.Equals (". aspx") || FileInfo mới (tệp) .Extension.Equals (". ascx") ) '
Damith

3
Đừng quên .NET4 mới Directory.EnumerateFilesđể tăng hiệu suất ... stackoverflow.com/questions/5669617/ trên
drzaus

6
Và bạn luôn có thể sử dụng file.EndsWith("...", StringComparison.InvariantCultureIgnoreCase);thay vìToLower
drzaus

30

GetFiles chỉ có thể khớp với một mẫu duy nhất, nhưng bạn có thể sử dụng Linq để gọi GetFiles với nhiều mẫu:

FileInfo[] fi = new string[]{"*.txt","*.doc"}
    .SelectMany(i => di.GetFiles(i, SearchOption.AllDirectories))
    .ToArray();

Xem phần bình luận tại đây: http://www.codeproject.com/KB/aspnet/NET_DirectoryInfo.aspx


2
Chúng sẽ va chạm nếu các mẫu chồng lên nhau. Ví dụ new string[]{"*.txt","filename.*"}. Tuy nhiên, lệnh gọi Distinctkhông thực sự giải quyết vấn đề này, vì các đối tượng FileInfo so sánh bằng cách sử dụng đẳng thức tham chiếu, không phải là đẳng thức ngữ nghĩa. Nó có thể được sửa bằng cách loại bỏ Distincthoặc chuyển nó đi IEqualityComparer<FileInfo>. Chỉnh sửa để làm trước đây.
Brian

Tôi nghĩ rằng điều đó SelectManysẽ lặp đi lặp lại trên cùng một cấu trúc tệp (và một lần nữa) để nó có thể không tối ưu về mặt hiệu suất.
Dejan

28

Tôi thích phương pháp này, vì nó có thể đọc được và tránh được nhiều lần lặp của thư mục:

var allowedExtensions = new [] {".doc", ".docx", ".pdf", ".ppt", ".pptx", ".xls", ".xslx"}; 
var files = Directory
    .GetFiles(folder)
    .Where(file => allowedExtensions.Any(file.ToLower().EndsWith))
    .ToList();

2
Tôi thích điều này tốt hơn nhiều vì tôi không phải phân tích mảng mở rộng của mình và thêm nó vào regex hoặc công việc thủ công khác. Cảm ơn!
Ian Newland

@Jodrell, hoặc đơn giản làHashSet<string>
Jodrell

Hashset <string> thay vì một mảng cho tiện ích mở rộng không có ý nghĩa gì ở đây, vì số lượng tiện ích mở rộng bị hạn chế và mảng được lặp lại cho mỗi tệp, cho đến khi EndsWith () trở thành sự thật. Nếu phương thức cần được điều chỉnh để thực hiện cho số lượng tiện ích mở rộng rất lớn, Hashset có thể được sử dụng. Để có hiệu lực, phần mở rộng của mỗi tệp sau đó cần phải được khớp một cách rõ ràng (tách, sau đó khớp) thay vì phương thức EndsWith () -. Điều này sẽ gây hại cho khả năng đọc và sẽ không được sử dụng đáng kể trong hầu hết các trường hợp sử dụng thực tế. Tôi đã quay trở lại chỉnh sửa cộng đồng.
Marc

15

Tôi sợ bạn sẽ phải làm một cái gì đó như thế này, tôi đã biến đổi regex từ đây .

var searchPattern = new Regex(
    @"$(?<=\.(aspx|ascx))", 
    RegexOptions.IgnoreCase);
var files = Directory.EnumerateFiles(path)
    .Where(f => searchPattern.IsMatch(f))
    .ToList();

Đây có vẻ là một cách tiếp cận tốt, phần còn thiếu là có một biểu thức thường xuyên được kiểm tra (làm việc)
Junior Mayhé

14
var filteredFiles = Directory
    .EnumerateFiles(path, "*.*") // .NET4 better than `GetFiles`
    .Where(
        // ignorecase faster than tolower...
        file => file.ToLower().EndsWith("aspx")
        || file.EndsWith("ascx", StringComparison.OrdinalIgnoreCase))
    .ToList();

Hoặc, có thể nhanh hơn để phân chia và hợp nhất các khối của bạn (ít nhất là nó trông sạch hơn):

"*.ext1;*.ext2".Split(';')
    .SelectMany(g => Directory.EnumerateFiles(path, g))
    .ToList();

và đăng lại câu hỏi "gốc" với nhiều chi tiết hơn - stackoverflow.com/questions/163162/iêu
drzaus

6

Giải pháp dễ nhớ, lười biếng và có lẽ không hoàn hảo:

Directory.GetFiles(dir, "*.dll").Union(Directory.GetFiles(dir, "*.exe"))

4

Tôi sẽ sử dụng như sau:

var ext = new string[] { ".ASPX", ".ASCX" };
FileInfo[] collection = (from fi in new DirectoryInfo(path).GetFiles()
                         where ext.Contains(fi.Extension.ToUpper())
                         select fi)
                         .ToArray();

EDIT: đã sửa lỗi không khớp giữa Directory và DirectoryInfo


3

Một cách hiệu quả hơn để nhận các tệp có phần mở rộng ".aspx" và ".ascx" để tránh truy vấn hệ thống tệp nhiều lần và tránh trả lại nhiều tệp không mong muốn, là lọc trước các tệp bằng cách sử dụng mẫu tìm kiếm gần đúng và để tinh chỉnh kết quả sau đó:

var filteredFiles = Directory.GetFiles(path, "*.as?x")
    .Select(f => f.ToLowerInvariant())
    .Where(f => f.EndsWith("px") || f.EndsWith("cx"))
    .ToList();

2

Tôi sẽ cố gắng chỉ định một cái gì đó như

var searchPattern = "as?x";

nó nên hoạt động


Hừ! Tôi sợ rằng aspx và ascx quá giống nhau và sẽ đưa ra một giải pháp hack như thế này. Tôi muốn một cái gì đó chung chung.
Seb Nilsson

2
    /// <summary>
    /// Returns the names of files in a specified directories that match the specified patterns using LINQ
    /// </summary>
    /// <param name="srcDirs">The directories to seach</param>
    /// <param name="searchPatterns">the list of search patterns</param>
    /// <param name="searchOption"></param>
    /// <returns>The list of files that match the specified pattern</returns>
    public static string[] GetFilesUsingLINQ(string[] srcDirs,
         string[] searchPatterns,
         SearchOption searchOption = SearchOption.AllDirectories)
    {
        var r = from dir in srcDirs
                from searchPattern in searchPatterns
                from f in Directory.GetFiles(dir, searchPattern, searchOption)
                select f;

        return r.ToArray();
    }

2
    public static bool CheckFiles(string pathA, string pathB)
    {
        string[] extantionFormat = new string[] { ".war", ".pkg" };
        return CheckFiles(pathA, pathB, extantionFormat);
    }
    public static bool CheckFiles(string pathA, string pathB, string[] extantionFormat)
    {
        System.IO.DirectoryInfo dir1 = new System.IO.DirectoryInfo(pathA);
        System.IO.DirectoryInfo dir2 = new System.IO.DirectoryInfo(pathB);
        // Take a snapshot of the file system. list1/2 will contain only WAR or PKG 
        // files
        // fileInfosA will contain all of files under path directories 
        FileInfo[] fileInfosA = dir1.GetFiles("*.*", 
                              System.IO.SearchOption.AllDirectories);
        // list will contain all of files that have ..extantion[]  
        // Run on all extantion in extantion array and compare them by lower case to 
        // the file item extantion ...
        List<System.IO.FileInfo> list1 = (from extItem in extantionFormat
                                          from fileItem in fileInfosA
                                          where extItem.ToLower().Equals 
                                          (fileItem.Extension.ToLower())
                                          select fileItem).ToList();
        // Take a snapshot of the file system. list1/2 will contain only WAR or  
        // PKG files
        // fileInfosA will contain all of files under path directories 
        FileInfo[] fileInfosB = dir2.GetFiles("*.*", 
                                       System.IO.SearchOption.AllDirectories);
        // list will contain all of files that have ..extantion[]  
        // Run on all extantion in extantion array and compare them by lower case to 
        // the file item extantion ...
        List<System.IO.FileInfo> list2 = (from extItem in extantionFormat
                                          from fileItem in fileInfosB
                                          where extItem.ToLower().Equals            
                                          (fileItem.Extension.ToLower())
                                          select fileItem).ToList();
        FileCompare myFileCompare = new FileCompare();
        // This query determines whether the two folders contain 
        // identical file lists, based on the custom file comparer 
        // that is defined in the FileCompare class. 
        return list1.SequenceEqual(list2, myFileCompare);
    }

2

Thay vì hàm EndsWith, tôi sẽ chọn sử dụng Path.GetExtension()phương thức thay thế. Dưới đây là ví dụ đầy đủ:

var filteredFiles = Directory.EnumerateFiles( path )
.Where(
    file => Path.GetExtension(file).Equals( ".aspx", StringComparison.OrdinalIgnoreCase ) ||
            Path.GetExtension(file).Equals( ".ascx", StringComparison.OrdinalIgnoreCase ) );

hoặc là:

var filteredFiles = Directory.EnumerateFiles(path)
.Where(
    file => string.Equals( Path.GetExtension(file), ".aspx", StringComparison.OrdinalIgnoreCase ) ||
            string.Equals( Path.GetExtension(file), ".ascx", StringComparison.OrdinalIgnoreCase ) );

(Sử dụng StringComparison.OrdinalIgnoreCasenếu bạn quan tâm đến hiệu suất: so sánh chuỗi MSDN )


1

trông giống như bản demo này:

void Main()
{
    foreach(var f in GetFilesToProcess("c:\\", new[] {".xml", ".txt"}))
        Debug.WriteLine(f);
}
private static IEnumerable<string> GetFilesToProcess(string path, IEnumerable<string> extensions)
{
   return Directory.GetFiles(path, "*.*")
       .Where(f => extensions.Contains(Path.GetExtension(f).ToLower()));
}

1
Bạn có Path.GetExtensionmà bạn có thể sử dụng.
jgauffin

1

@Daniel B, cảm ơn bạn đã gợi ý viết phiên bản chức năng này của riêng tôi. Nó có hành vi tương tự như Directory.GetFiles, nhưng hỗ trợ lọc regex.

string[] FindFiles(FolderBrowserDialog dialog, string pattern)
    {
        Regex regex = new Regex(pattern);

        List<string> files = new List<string>();
        var files=Directory.GetFiles(dialog.SelectedPath);
        for(int i = 0; i < files.Count(); i++)
        {
            bool found = regex.IsMatch(files[i]);
            if(found)
            {
                files.Add(files[i]);
            }
        }

        return files.ToArray();
    }

Tôi thấy nó hữu ích, vì vậy tôi nghĩ tôi muốn chia sẻ.


1

phiên bản c # của câu trả lời của @ qfactor77. Đây là cách tốt nhất mà không có LINQ.

string[] wildcards= {"*.mp4", "*.jpg"};
ReadOnlyCollection<string> filePathCollection = FileSystem.GetFiles(dirPath, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, wildcards);
string[] filePath=new string[filePathCollection.Count];
filePathCollection.CopyTo(filePath,0);

Bây giờ trả về filePathmảng chuỗi. Lúc đầu bạn cần

using Microsoft.VisualBasic.FileIO;
using System.Collections.ObjectModel;

bạn cũng cần thêm tài liệu tham khảo Microsoft.VisualBasic


1

Tôi đã thực hiện một cách đơn giản để tìm kiếm nhiều tiện ích mở rộng mà bạn cần và không có ToLower (), RegEx, foreach ...

List<String> myExtensions = new List<String>() { ".aspx", ".ascx", ".cs" }; // You can add as many extensions as you want.
DirectoryInfo myFolder = new DirectoryInfo(@"C:\FolderFoo");
SearchOption option = SearchOption.TopDirectoryOnly; // Use SearchOption.AllDirectories for seach in all subfolders.
List<FileInfo> myFiles = myFolder.EnumerateFiles("*.*", option)
    .Where(file => myExtensions
    .Any(e => String.Compare(file.Extension, e, CultureInfo.CurrentCulture, CompareOptions.IgnoreCase) == 0))
    .ToList();

Hoạt động trên .Net Standard 2.0.


1

Bạn có thể làm như thế này

new DirectoryInfo(path).GetFiles().Where(Current => Regex.IsMatch(Current.Extension, "\\.(aspx|ascx)", RegexOptions.IgnoreCase)

Trong câu hỏi là: LINQ không phải là một lựa chọn, vì vậy câu trả lời này không hữu ích
Arci

0
var filtered = Directory.GetFiles(path)
    .Where(file => file.EndsWith("aspx", StringComparison.InvariantCultureIgnoreCase) || file.EndsWith("ascx", StringComparison.InvariantCultureIgnoreCase))
    .ToList();

Thêm giải thích bổ sung cho mã. Nó có thể giúp OP hiểu câu trả lời của bạn tốt hơn.
dùng2339071

-2

Chỉ muốn nói rằng nếu bạn sử dụng FileIO.FileSystem.GetFilesthay vì Directory.GetFiles, nó sẽ cho phép một loạt các ký tự đại diện.

Ví dụ:

Dim wildcards As String() = {"*.html", "*.zip"}
Dim ListFiles As List(Of String) = FileIO.FileSystem.GetFiles(directoryyouneed, FileIO.SearchOption.SearchTopLevelOnly, wildcards).ToList

Trường hợp nào có được FileIO?
Joel Martinez

1
Nó đã được đưa vào môi trường của bạn trong Visual Studio (2015). Nó là một phần của không gian tên Microsoft.VisualBasic. Trong trường hợp của tôi là VisualBasic vì đó là ngôn ngữ tôi chọn.
qfactor77
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.