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.

Seb Nilsson
sumber
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));
}
Daniel B
sumber
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

jgauffin.dll
sumber
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();
Marc
sumber
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

Ulrik Magnusson
sumber
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();
drzaus
sumber
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();
Jodrell
sumber
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"))
jonathan
sumber
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

Mario Vernari
sumber
3

Saya akan mencoba menentukan sesuatu seperti

var searchPattern = "as?x";

itu harus bekerja.

Davide Piras
sumber
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();
Olivier Jacot-Descombes
sumber
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();
    }
A. Ramazani
sumber
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);
    }
yossi goldberg
sumber
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 )

BigChief
sumber
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()));
}
Gildor
sumber
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.

Artorias 2718
sumber
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

Rijul Sudhir
sumber
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.

Carlos David López
sumber
1

Anda bisa melakukannya seperti ini

new DirectoryInfo(path).GetFiles().Where(Current => Regex.IsMatch(Current.Extension, "\\.(aspx|ascx)", RegexOptions.IgnoreCase)
Gigabyte
sumber
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();
Roma
sumber
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
qfactor77
sumber
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