หลายนามสกุลไฟล์ searchPattern สำหรับ System.IO.Directory.GetFiles


140

ไวยากรณ์สำหรับการตั้งค่าคืออะไรหลาย ๆ ไฟล์นามสกุลเป็นsearchPatternบนDirectory.GetFiles()? ยกตัวอย่างเช่นการกรองไฟล์ที่มีขอบและ.ascxนามสกุล

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

อัปเดต : LINQ ไม่ใช่ตัวเลือกแต่จะต้องมีการsearchPatternส่งผ่านไปยังGetFilesตามที่ระบุในคำถาม


ฉันไม่คิดว่ามี แสดงรายการไฟล์ทั้งหมดจากนั้นกรองด้วยตนเองหรือดำเนินการกับยูเนี่ยนกับผู้ค้นหาหลายคน แต่ฉันค่อนข้างแน่ใจว่าฉันเคยเห็นคำถามตรงนี้ใน SO มาก่อน
CodesInChaos


ถามและตอบก่อนหน้านี้ที่นี่: stackoverflow.com/questions/163162/…
David

คำตอบ:


41

ฉันเชื่อว่าไม่มีทางออก "ออกจากกล่อง" นั่นเป็นข้อ จำกัด ของวิธีการ Directory.GetFiles

มันค่อนข้างง่ายที่จะเขียนวิธีการของคุณเอง แต่นี่เป็นตัวอย่าง

รหัสอาจเป็น:

/// <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
นี่เป็นวิธีที่ไม่เพียงพอในการทำเช่นนี้เนื่องจากคุณจะวนซ้ำทั้งไดเรกทอรีสำหรับตัวกรองแต่ละตัว แต่คุณควรตรวจสอบแต่ละไฟล์ว่ามีตัวกรองอยู่หรือไม่และเพิ่มในรายการ คุณสามารถใช้คำตอบที่อธิบายไว้ในหัวข้อนี้: stackoverflow.com/questions/3754118/…
ot0

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

แก้ไข 2014-07-23

คุณสามารถทำได้ใน. NET 4.5 เพื่อการแจงนับที่เร็วขึ้น:

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

Directory.EnumerateFiles ใน MSDN


5
@Mario Vernari: ผลตอบแทนGetFiles string[]
jgauffin

4
คุณต้องลบเครื่องหมาย * ออกจากอาร์กิวเมนต์ EndsWith () ซึ่งไม่ตรงกับอักขระตัวแทน
Hans Passant

3
ถ้าเปรียบเทียบนามสกุลของไฟล์มันจะคืนค่าการจับคู่ที่ตรงกันเช่น '. ที่ไหน (ไฟล์ => ใหม่ FileInfo (ไฟล์) .Extension.Equals (". aspx") || ใหม่ FileInfo (ไฟล์) .Extension.Equals (". ascx") ) '
Damith

3
อย่าลืม. NET4 ใหม่Directory.EnumerateFilesเพื่อเพิ่มประสิทธิภาพ ... stackoverflow.com/questions/5669617/
drzaus

6
และคุณก็สามารถใช้file.EndsWith("...", StringComparison.InvariantCultureIgnoreCase);มากกว่าToLower
drzaus

30

GetFiles สามารถจับคู่รูปแบบเดียวเท่านั้น แต่คุณสามารถใช้ Linq เพื่อเรียกใช้ GetFiles ที่มีหลายรูปแบบ:

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

ดูส่วนความเห็นที่นี่: http://www.codeproject.com/KB/aspnet/NET_DirectoryInfo.aspx


2
พวกเขาจะชนกันหากรูปแบบทับซ้อนกัน เช่นnew string[]{"*.txt","filename.*"}. อย่างไรก็ตามการเรียกไปDistinctยังไม่สามารถแก้ไขปัญหานี้ได้จริงเนื่องจากวัตถุ FileInfo เปรียบเทียบโดยใช้ความเท่าเทียมกันของการอ้างอิงไม่ใช่ความเท่าเทียมกันทางความหมาย มันอาจจะได้รับการแก้ไขโดยการถอดหรือผ่านเป็นDistinct IEqualityComparer<FileInfo>แก้ไขเพื่อทำอดีต
Brian

ฉันคิดว่ามันSelectManyจะทำซ้ำโครงสร้างไฟล์เดียวกันอีกครั้ง (และอีกครั้ง) ดังนั้นจึงอาจดีที่สุดในแง่ของประสิทธิภาพ
Dejan

28

ฉันชอบวิธีนี้เพราะสามารถอ่านได้และหลีกเลี่ยงการวนซ้ำของไดเรกทอรี:

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

2
ฉันชอบสิ่งนี้มากขึ้นเพราะฉันไม่ต้องแยกอาร์เรย์ส่วนขยายของฉันและเพิ่มลงใน regex หรืองานอื่น ๆ ด้วยตนเอง ขอบคุณ!
Ian Newland

@Jodrell หรือเพียงแค่HashSet<string>
Jodrell

HashSet <string> แทนที่จะเป็นอาเรย์สำหรับส่วนขยายไม่สมเหตุสมผลที่นี่เนื่องจากจำนวนของส่วนขยายถูก จำกัด และอาร์เรย์ได้รับการวนซ้ำสำหรับแต่ละไฟล์จนถึง EndsWith () จะได้รับจริง หากวิธีการนั้นต้องได้รับการปรับแต่งเพื่อให้มีประสิทธิภาพสำหรับส่วนขยายจำนวนมากคุณสามารถใช้ Hashset ได้ เพื่อให้มีผลบังคับใช้ส่วนขยายของแต่ละไฟล์จะต้องมีการจับคู่อย่างชัดเจน (แยกแล้วจับคู่) แทนเมธอด EndsWith () - สิ่งนี้จะเป็นอันตรายต่อความสามารถในการอ่านและจะไม่มีการใช้อย่างมีนัยสำคัญในกรณีส่วนใหญ่หากไม่ได้ใช้งานจริง ฉันย้อนกลับไปแก้ไขชุมชน
Marc

15

ฉันกลัวคุณจะต้องทำ Somthing เช่นนี้ผมกลายพันธุ์ regex จากที่นี่

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

นี่ดูเหมือนจะเป็นวิธีที่ดีส่วนที่ขาดหายไปก็คือการแสดงออกปกติ (ที่ใช้งาน) ที่ผ่านการทดสอบแล้ว
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();

หรืออาจเร็วกว่าที่จะแยกและผสาน globs ของคุณ (อย่างน้อยก็ดูสะอาดกว่า):

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

และการโพสต์ข้อความคำถาม "ดั้งเดิม" อีกครั้งพร้อมรายละเอียดเพิ่มเติม - stackoverflow.com/questions/163162/…
drzaus


4

ฉันจะใช้สิ่งต่อไปนี้:

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

แก้ไข: แก้ไขไม่ตรงกันเนื่องจาก Directory และ DirectoryInfo


3

วิธีที่มีประสิทธิภาพมากขึ้นในการรับไฟล์ที่มีนามสกุล ".aspx" และ ".ascx" ที่หลีกเลี่ยงการสืบค้นระบบไฟล์หลายครั้งและหลีกเลี่ยงการส่งคืนไฟล์ที่ไม่พึงประสงค์จำนวนมากคือการกรองไฟล์ล่วงหน้าโดยใช้รูปแบบการค้นหาโดยประมาณและ เพื่อปรับแต่งผลลัพธ์ในภายหลัง:

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

2

ฉันจะพยายามระบุสิ่งที่ชอบ

var searchPattern = "as?x";

มันควรจะทำงาน


ฮะ! ฉันกลัวว่า aspx และ ascx คล้ายกันมากเกินไปและจะทำให้แฮ็กโซลูชันเช่นนี้ ฉันต้องการของทั่วไป
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

แทนที่จะใช้ฟังก์ชัน EndsWith ฉันจะเลือกใช้Path.GetExtension()วิธีแทน นี่คือตัวอย่างเต็มรูปแบบ:

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

หรือ:

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

(ใช้StringComparison.OrdinalIgnoreCaseถ้าคุณสนใจเกี่ยวกับประสิทธิภาพ: การเปรียบเทียบสตริง MSDN )


1

ดูเหมือนตัวอย่างนี้:

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
คุณมีPath.GetExtensionสิ่งที่คุณสามารถใช้
jgauffin

1

@Daniel B ขอบคุณสำหรับคำแนะนำในการเขียนฟังก์ชั่นนี้ในเวอร์ชั่นของฉันเอง มันมีพฤติกรรมเช่นเดียวกับ Directory.GetFiles แต่รองรับการกรอง 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();
    }

ฉันพบว่ามีประโยชน์ดังนั้นฉันคิดว่าฉันจะแบ่งปัน


1

คำตอบของ @ qfactor77 รุ่น 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);

ตอนนี้กลับfilePathอาร์เรย์สตริง ในการเริ่มต้นที่คุณต้องการ

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

นอกจากนี้คุณต้องเพิ่มการอ้างอิงถึง Microsoft.VisualBasic


1

ฉันทำวิธีง่ายๆในการค้นหาส่วนขยายได้มากเท่าที่คุณต้องการและไม่มี 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();

ทำงานบน. Net Standard 2.0


1

คุณสามารถทำได้เช่นนี้

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

ในคำถามคือ: LINQ ไม่ใช่ตัวเลือกดังนั้นคำตอบนี้ไม่มีประโยชน์
Arci

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

เพิ่มคำอธิบายเพิ่มเติมสำหรับรหัส มันอาจช่วยให้ OP เข้าใจคำตอบของคุณดีขึ้น
user2339071

-2

แค่อยากจะบอกว่าถ้าคุณใช้FileIO.FileSystem.GetFilesแทนDirectory.GetFilesมันจะอนุญาตให้ใช้สัญลักษณ์แทนได้

ตัวอย่างเช่น:

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

ใครจะได้รับFileIO?
Joel Martinez

1
มันควรจะรวมอยู่ในสภาพแวดล้อมของคุณใน Visual Studio (2015) มันเป็นส่วนหนึ่งของ namespace Microsoft.VisualBasic ในกรณีของฉันคือ VisualBasic เพราะนั่นคือภาษาที่ฉันเลือก
qfactor77
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.