Beberapa ekstensi file searchPattern untuk System.IO.Directory.GetFiles


146

Apa sintaks untuk menyetel beberapa ekstensi file seperti searchPatternpada Directory.GetFiles()? Misalnya memfilter file dengan ekstensi .aspx dan .ascx .

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

Pembaruan : LINQ bukanlah pilihan , itu harus searchPatternditeruskan ke GetFiles, sebagaimana ditentukan dalam pertanyaan.


Saya rasa tidak ada. Buat daftar semua file dan kemudian filter secara manual atau lakukan penyatuan di beberapa pencari. Tapi saya cukup yakin saya pernah melihat pertanyaan yang tepat ini di SO sebelumnya.
CodesInChaos


Sebelumnya ditanyakan dan dijawab di sini: stackoverflow.com/questions/163162/…
David

Mengapa LINQ tidak pernah menjadi pilihan? Ini adalah perpustakaan yang sangat umum di .NET dan harus digunakan bila diperlukan.
Mark Entingh

Jawaban:


45

Saya percaya tidak ada solusi "di luar kotak", itu adalah batasan dari metode Directory.GetFiles.

Namun, cukup mudah untuk menulis metode Anda sendiri, berikut ini contohnya .

Kodenya bisa jadi:

/// <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
Ini adalah cara yang sangat tidak memadai untuk melakukannya, karena Anda akan mengulang seluruh direktori untuk setiap filter. Sebaliknya Anda harus memeriksa setiap file jika memiliki filter kemudian tambahkan untuk melakukan daftar. Anda dapat menggunakan jawaban yang dijelaskan di utas ini: stackoverflow.com/questions/3754118/…
ot0

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

Sunting 2014-07-23

Anda dapat melakukan ini di .NET 4.5 untuk penghitungan yang lebih cepat:

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

Directory.EnumerateFiles di MSDN


5
@ Mario Vernari: GetFileskembali string[].
jgauffin

4
Anda harus menghapus * dari argumen EndsWith (), itu tidak melakukan kecocokan karakter pengganti.
Hans Passant

3
jika membandingkan ekstensi file, ia akan mengembalikan kecocokan persis seperti '.Where (file => new FileInfo (file) .Extension.Equals (". aspx") || new FileInfo (file) .Extension.Equals (". ascx") ) '
Damith

3
Jangan lupakan .NET4 baru Directory.EnumerateFilesuntuk meningkatkan kinerja ... stackoverflow.com/questions/5669617/…
drzaus

6
Dan Anda selalu dapat menggunakan file.EndsWith("...", StringComparison.InvariantCultureIgnoreCase);daripadaToLower
drzaus

34

Saya suka metode ini, karena dapat dibaca dan menghindari beberapa iterasi direktori:

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

2
Saya menyukai ini jauh lebih baik karena saya tidak perlu mengurai array ekstensi saya dan menambahkannya ke regex atau pekerjaan manual lainnya. Terima kasih!
Ian Newland

@Jodrell, atau hanyaHashSet<string>
Jodrell

HashSet <string> alih-alih array untuk ekstensi tidak masuk akal di sini, karena jumlah ekstensi dibatasi dan array diulang untuk setiap file, sampai EndsWith () menjadi true. Jika metode tersebut perlu disetel untuk kinerja untuk sejumlah besar ekstensi, Hashset dapat digunakan. Agar dapat diterapkan, ekstensi setiap file kemudian harus dicocokkan secara eksplisit (dipisahkan, lalu cocokkan) alih-alih metode EndsWith () -. Ini akan merusak readibility dan tidak akan berguna di sebagian besar, jika tidak semua kasus penggunaan di kehidupan nyata. Oleh karena itu, saya memutar kembali hasil edit komunitas.
Marc

30

GetFiles hanya dapat mencocokkan satu pola, tetapi Anda dapat menggunakan Linq untuk menjalankan GetFiles dengan beberapa pola:

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

Lihat bagian komentar di sini: http://www.codeproject.com/KB/aspnet/NET_DirectoryInfo.aspx


2
Mereka akan bertabrakan jika polanya tumpang tindih. Misalnya new string[]{"*.txt","filename.*"},. Namun, panggilan ke Distincttidak benar-benar menyelesaikan masalah ini, karena objek FileInfo dibandingkan menggunakan persamaan referensi, bukan persamaan semantik. Itu bisa diperbaiki dengan menghapus Distinctatau meneruskannya IEqualityComparer<FileInfo>. Diedit untuk melakukan yang pertama.
Brian

Saya akan berpikir itu SelectManyakan mengulangi struktur file yang sama lagi (dan lagi) sehingga mungkin kurang optimal dalam hal kinerja.
Dejan

15
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();

Atau, mungkin lebih cepat untuk membagi dan menggabungkan glob Anda (setidaknya terlihat lebih bersih):

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

dan memposting ulang pada pertanyaan "asli" dengan lebih detail - stackoverflow.com/questions/163162/…
drzaus

15

Saya khawatir Anda harus melakukan hal seperti ini, saya mutasi regex dari sini .

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

ini tampaknya pendekatan yang bagus, bagian yang hilang adalah memiliki ekspresi reguler yang teruji (berfungsi)
Junior Mayhé

6

Solusi yang mudah diingat, malas, dan mungkin tidak sempurna:

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

Tidak berfungsi jika menggunakan SearchOption
NadimAJ

4

Saya akan menggunakan yang berikut ini:

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: diperbaiki karena ketidakcocokan antara Directory dan DirectoryInfo


3

Saya akan mencoba menentukan sesuatu seperti

var searchPattern = "as?x";

itu harus bekerja.


1
Hah! Saya takut aspx dan ascx terlalu mirip dan akan membuat solusi hack seperti ini. Saya ingin sesuatu yang umum.
Seb Nilsson

3

Cara yang lebih efisien untuk mendapatkan file dengan ekstensi ".aspx" dan ".ascx" yang menghindari kueri sistem file beberapa kali dan menghindari mengembalikan banyak file yang tidak diinginkan, adalah dengan melakukan pra-filter file dengan menggunakan pola pencarian perkiraan dan untuk mempersempit hasil setelahnya:

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

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

Alih-alih fungsi EndsWith, saya akan memilih untuk menggunakan Path.GetExtension()metode sebagai gantinya. Berikut contoh lengkapnya:

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

atau:

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

(Gunakan StringComparison.OrdinalIgnoreCasejika Anda peduli dengan kinerja: perbandingan string MSDN )


1

terlihat seperti demo ini:

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
Anda memiliki Path.GetExtensionyang dapat Anda gunakan.
jgauffin

1

@Daniel B, terima kasih atas saran untuk menulis versi saya sendiri untuk fungsi ini. Ini memiliki perilaku yang sama seperti Directory.GetFiles, tetapi mendukung pemfilteran 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();
    }

Saya merasa itu berguna, jadi saya pikir saya akan berbagi.


1

c # versi jawaban @ qfactor77. Ini adalah cara terbaik tanpa 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);

sekarang kembalikan filePathlarik string. Pada awalnya Anda membutuhkan

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

Anda juga perlu menambahkan referensi ke Microsoft.VisualBasic


1

Saya melakukan cara sederhana untuk mencari ekstensi sebanyak yang Anda butuhkan, dan tanpa 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();

Bekerja pada .Net Standard 2.0.


1

Anda bisa melakukannya seperti ini

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

Pertanyaannya adalah: LINQ bukanlah pilihan, jadi jawaban ini tidak berguna
Arci

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

Tambahkan penjelasan tambahan untuk kode tersebut. Ini mungkin membantu OP memahami jawaban Anda dengan lebih baik.
pengguna2339071

-1

Hanya ingin mengatakan bahwa jika Anda menggunakan FileIO.FileSystem.GetFilesalih-alih Directory.GetFiles, ini akan memungkinkan serangkaian karakter pengganti.

Sebagai contoh:

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

Dimana seseorang memperolehnya FileIO?
Joel Martinez

1
Ini harus sudah termasuk dalam lingkungan Anda di Visual Studio (2015). Ini adalah bagian dari namespace Microsoft.VisualBasic. Dalam kasus saya adalah VisualBasic karena itulah bahasa pilihan saya.
qfactor77
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.