คุณสามารถโทร Directory.GetFiles () พร้อมตัวกรองหลายตัวได้หรือไม่


353

ฉันกำลังพยายามใช้Directory.GetFiles()วิธีการเพื่อเรียกคืนรายการไฟล์หลายประเภทเช่นmp3's และjpg' s ฉันได้ลองทั้งสองอย่างโดยไม่มีโชค:

Directory.GetFiles("C:\\path", "*.mp3|*.jpg", SearchOption.AllDirectories);
Directory.GetFiles("C:\\path", "*.mp3;*.jpg", SearchOption.AllDirectories);

มีวิธีการในการโทรครั้งเดียวหรือไม่?


3
หมายเหตุด้านการใช้รูปแบบการค้นหาของ GetFiles สำหรับการกรองส่วนขยายนั้นไม่ปลอดภัยตัวอย่างเช่นคุณมีไฟล์ Test1.xls และ Test2.xlsx สองไฟล์และคุณต้องการกรองไฟล์ xls โดยใช้รูปแบบการค้นหา * .xls แต่ GetFiles ส่งคืนทั้ง Test1 .xls และ Test2.xlsx อ่านส่วนหมายเหตุสำหรับข้อมูลเพิ่มเติม
kiran

ดังนั้นวิธีการป้องกันนี้
วงเล็บ

2
@kiran นั่นมันไม่ปลอดภัยเหรอ? ที่ดูเหมือนว่าคุณสมบัติมากกว่าข้อผิดพลาด
Kyle Delaney

คำตอบ:


519

สำหรับ. NET 4.0 และใหม่กว่า

var files = Directory.EnumerateFiles("C:\\path", "*.*", SearchOption.AllDirectories)
            .Where(s => s.EndsWith(".mp3") || s.EndsWith(".jpg"));

สำหรับ. NET รุ่นก่อนหน้า

var files = Directory.GetFiles("C:\\path", "*.*", SearchOption.AllDirectories)
            .Where(s => s.EndsWith(".mp3") || s.EndsWith(".jpg"));

แก้ไข: โปรดอ่านความคิดเห็น การปรับปรุงที่Paul Farryแนะนำและปัญหาด้านหน่วยความจำ / ประสิทธิภาพที่Christian.Kชี้ให้เห็นนั้นสำคัญมาก


10
ผู้ชายฉันต้องคิดในแง่ของ LINQ บ่อยขึ้น ทางออกที่ดี!
Ken Pespisa

61
ตรวจสอบให้แน่ใจว่าคุณเข้าใจความหมายที่เกี่ยวข้อง: สิ่งนี้จะส่งคืนไฟล์ทั้งหมดในอาร์เรย์สตริงแล้วกรองตามนามสกุลที่คุณระบุ นั่นอาจไม่ใช่ปัญหาใหญ่หาก "C: \ Path" ไม่มีไฟล์จำนวนมากอยู่ข้างใต้ แต่อาจเป็นปัญหาหน่วยความจำ / ประสิทธิภาพใน "C: \" หรืออะไรทำนองนั้น
Christian.K

24
... 2 ปีต่อมา: รหัสที่ดี แต่ระวังด้วยถ้าคุณมีไฟล์ที่ลงท้ายด้วย. JPG มันจะไม่ทำให้มัน เพิ่มที่ดีขึ้นs.ToLower().Endswith...
Stormenet

107
คุณสามารถใช้ได้s.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase)
Paul Farry

119
โปรดทราบว่ามี .NET 4.0 คุณสามารถแทนที่Directory.GetFilesด้วยDirectory.EnumerateFiles, msdn.microsoft.com/en-us/library/dd383571.aspxซึ่งจะหลีกเลี่ยงปัญหาหน่วยความจำที่ @ Christian.K กล่าว
Jim Mischel

60

เกี่ยวกับสิ่งนี้:

private static string[] GetFiles(string sourceFolder, string filters, System.IO.SearchOption searchOption)
{
   return filters.Split('|').SelectMany(filter => System.IO.Directory.GetFiles(sourceFolder, filter, searchOption)).ToArray();
}

ฉันพบมันที่นี่ (ในความคิดเห็น): http://msdn.microsoft.com/en-us/library/wz42302f.aspx


ฉันเดาว่านี่จะช่วยหลีกเลี่ยงข้อผิดพลาดที่อาจเกิดขึ้นกับคำตอบยอดนิยมหรือ ในกรณีนี้ควรได้รับการจัดอันดับสูงกว่า!
Dan W

11
@DANW คำตอบที่ได้รับความนิยมอันดับต้นย่อมสร้างภาระให้กับหน่วยความจำ แต่ฉันคิดว่าไม่น่าจะมีปัญหาอะไร ฉันชอบคำตอบนี้เหมือนกัน แต่จริงๆแล้วมันช้ากว่ามากแล้วคำตอบที่ได้รับการยอมรับ ตรวจสอบSpeedTest
อ็อตโต

ขอบคุณ ดีใจที่ได้เห็นมันช้ามากเพียงประมาณสองครั้ง - ฉันจะติดมันตลอดเวลาที่ฉันคิด
Dan W

7
ช้าเพียงสองเท่าหากมีเพียงสองส่วนขยาย หากคุณมีรายการส่วนขยาย X ดังนั้น X จะช้ากว่ามาก เนื่องจากที่นี่คุณกำลังเรียกใช้ฟังก์ชัน Directory.GetFiles หลายครั้งในขณะที่โซลูชันอื่นจะถูกเรียกเพียงครั้งเดียว
Oscar Hermosilla

1
@OscarHermosilla หนึ่งสามารถใช้Parallel.ForEachเพื่อให้พวกเขาในแบบคู่ขนาน
FindOutIslamNow

33

หากคุณมีรายการส่วนขยายจำนวนมากเพื่อตรวจสอบคุณสามารถใช้สิ่งต่อไปนี้ ฉันไม่ต้องการสร้างคำสั่ง OR จำนวนมากดังนั้นฉันจึงแก้ไขสิ่งที่ lette เขียน

string supportedExtensions = "*.jpg,*.gif,*.png,*.bmp,*.jpe,*.jpeg,*.wmf,*.emf,*.xbm,*.ico,*.eps,*.tif,*.tiff,*.g01,*.g02,*.g03,*.g04,*.g05,*.g06,*.g07,*.g08";
foreach (string imageFile in Directory.GetFiles(_tempDirectory, "*.*", SearchOption.AllDirectories).Where(s => supportedExtensions.Contains(Path.GetExtension(s).ToLower())))
{
    //do work here
}

โปรดช่วยฉันด้วย ... เมื่อฉันพิมพ์ภาพไฟล์มันให้เส้นทางทั้งหมดของมันฉันจะย่อขนาดให้เหลือแค่ชื่อของไฟล์ได้อย่างไร
Naresh

1
System.IO.Path.GetFileName (imageFile)
jnoreiga

Path.GetExtensionส่งคืน '.ext' ไม่ใช่ '* .ext' (อย่างน้อยใน 3.5+)
nullable

2
FYI: คุณต้องใช้ System.Linq สำหรับ .where (
jnoreiga

1
มีข้อบกพร่องที่อาจเกิดขึ้น เราใช้เวลานานพอสมควรในการขยายส่วนที่ต้องมีอักขระสามตัว สมมติว่าคุณอาจพบไฟล์ที่มีและมี.abc supportedExtensions .abcdจะจับคู่แม้ว่ามันจะไม่ควร ในการแก้ไขปัญหา: ด้วยsupportedExtensions = ".jpg|.abcd|"; .Contains(Path.GetExtension(s).ToLower() + "|")นั่นคือรวมถึงตัวคั่นของคุณในการทดสอบ สำคัญ: ตัวคั่นของคุณจะต้องอยู่หลังรายการสุดท้ายในการสนับสนุนที่ได้รับ
ToolmakerSteve

31

สำหรับ

var exts = new[] { "mp3", "jpg" };

คุณสามารถ:

public IEnumerable<string> FilterFiles(string path, params string[] exts) {
    return
        Directory
        .EnumerateFiles(path, "*.*")
        .Where(file => exts.Any(x => file.EndsWith(x, StringComparison.OrdinalIgnoreCase)));
}

แต่ประโยชน์ที่แท้จริงของการEnumerateFilesแสดงขึ้นเมื่อคุณแยกตัวกรองและรวมผลลัพธ์:

public IEnumerable<string> FilterFiles(string path, params string[] exts) {
    return 
        exts.Select(x => "*." + x) // turn into globs
        .SelectMany(x => 
            Directory.EnumerateFiles(path, x)
            );
}

มันจะเร็วขึ้นอีกเล็กน้อยถ้าคุณไม่ต้องทำให้มันกลายเป็น globs (เช่นexts = new[] {"*.mp3", "*.jpg"}แล้ว)

การประเมินประสิทธิภาพตามการทดสอบ LinqPad ดังต่อไปนี้ (หมายเหตุ: Perfเพียงทำซ้ำผู้ร่วมประชุม 10,000 ครั้ง) https://gist.github.com/zaus/7454021

(โพสต์ใหม่และขยายจาก 'ทำซ้ำ' เนื่องจากคำถามนั้นไม่ได้ขอ LINQ โดยเฉพาะ: นามสกุลไฟล์หลาย searchPattern สำหรับ System.IO.Directory.GetFiles )


คุณหมายถึงอะไรโดย "ฉันจะเร็วขึ้นอีกนิดถ้าคุณไม่ต้องเปลี่ยนมันให้เป็นสีเหลือง"? มันเป็น O (1) หรือเป็น O (n) (เกี่ยวกับจำนวนไฟล์ไม่ใช่จำนวนนามสกุล)? ฉันจะเดาได้ว่ามันเป็น O (1) (หรือ O (n) ในเรื่องที่เกี่ยวกับจำนวนของส่วนขยาย) และอาจจะอยู่ที่ไหนสักแห่งในช่วงไม่กี่ซีพียูรอบ ... ถ้าเป็นกรณีที่มันอาจจะ - ประสิทธิภาพการทำงานที่ชาญฉลาด - เล็กน้อย
BatteryBackupUnit

@BackBackupUnit ใช่ด้วย 10k reps ต่อ 2 ส่วนขยาย glob กับความแตกต่าง str คือ 3ms ดังนั้นใช่เล็กน้อยเทคนิค (ดูลิงค์ผลสมบูรณ์) แต่ไม่รู้จำนวนนามสกุลที่คุณต้องการกรองฉันคิดว่ามันคุ้มค่าชี้ให้เห็นว่ามี ความแตกต่าง; ฉันปล่อยให้คุณตัดสินใจว่า "การใช้งานแบบง่าย" (ie .FilterFiles(path, "jpg", "gif")) ดีกว่า "globs ชัดเจน" (เช่น.FilterFiles(path, "*.jpg", "*.gif"))
drzaus

สมบูรณ์แบบขอบคุณ ขออภัยฉันข้ามลิงค์ github นั้นไป บางทีฉันควรปรับการตั้งค่าสีของหน้าจอ :)
BatteryBackupUnit

สิ่งนี้รองรับส่วนขยายตัวพิมพ์ใหญ่เช่น. JPG หรือ. MKV หรือไม่
Wahyu

1
ข้อบกพร่องของโซลูชัน SelectMany คือมันจะวนซ้ำไฟล์ทั้งหมดหนึ่งครั้งต่อนามสกุลไฟล์ที่ส่งเข้า
17 จาก 26

16

ฉันรู้ว่ามันเป็นคำถามเก่า แต่ LINQ: (.NET40 +)

var files = Directory.GetFiles("path_to_files").Where(file => Regex.IsMatch(file, @"^.+\.(wav|mp3|txt)$"));

3
ความคิดที่ดี. ลองใช้file.ToLower()เพื่อจับคู่ส่วนขยายตัวใหญ่และตัวเล็กได้อย่างง่ายดาย และทำไมไม่แยกส่วนขยายออกก่อนดังนั้น Regex จึงไม่ต้องตรวจสอบเส้นทางทั้งหมด: Regex.IsMatch(Path.GetExtension(file).ToLower(), @"\.(wav|mp3|txt)");
ToolmakerSteve

13

นอกจากนี้ยังมีวิธีแก้ปัญหาเชื้อสายซึ่งดูเหมือนว่าจะไม่มีหน่วยความจำหรือค่าใช้จ่ายในการดำเนินงานและมีความสง่างาม:

string[] filters = new[]{"*.jpg", "*.png", "*.gif"};
string[] filePaths = filters.SelectMany(f => Directory.GetFiles(basePath, f)).ToArray();

1
ฉันคิดว่าฉันสามารถแก้ไขได้เพื่อที่จะยอมรับส่วนขยายไม่ จำกัด จำนวนไม่ทราบด้วยตัวแปรสตริงใหม่และฟังก์ชั่นสปลิต แต่ถึงอย่างนั้นจะดีกว่าวิธีการแก้ปัญหาของ jnoreiga อย่างไร เร็วขึ้นไหม ใช้หน่วยความจำน้อยลงหรือไม่
วงเล็บ

1
มีการแลกเปลี่ยนเป็น วิธีการนี้เรียกใช้ GetFiles หลายครั้งต่อหนึ่งตัวกรอง การเรียกหลายครั้งนั้นอาจเป็น "ค่าใช้จ่ายด้านประสิทธิภาพ" อย่างมีนัยสำคัญในบางสถานการณ์มันมีข้อได้เปรียบที่สำคัญที่ GetFiles แต่ละรายการจะส่งคืนอาร์เรย์ด้วยพา ธ ของไฟล์ที่ตรงกันเท่านั้น ฉันคาดหวังว่าสิ่งนี้มักจะเป็นผลงานที่ดีหรืออาจจะเป็นประสิทธิภาพที่เหนือกว่าแต่ก็ต้องมีการทดสอบ ถ้า GetFiles เร็วกว่า EnumerateFiles อย่างมากนี่อาจเป็นวิธีที่ดีที่สุด นอกจากนี้โปรดทราบว่าสามารถละเว้น ".ToArray ()" ขั้นสุดท้ายได้เมื่อ IEnumerable สามารถใช้งานได้โดยตรง
ToolmakerSteve

11

อีกวิธีในการใช้ Linq แต่ไม่ต้องส่งคืนทุกสิ่งและกรองข้อมูลนั้นในหน่วยความจำ

var files = Directory.GetFiles("C:\\path", "*.mp3", SearchOption.AllDirectories).Union(Directory.GetFiles("C:\\path", "*.jpg", SearchOption.AllDirectories));

มันคือการโทร 2 GetFiles()ครั้ง แต่ฉันคิดว่ามันสอดคล้องกับจิตวิญญาณของคำถามและส่งคืนพวกเขาในจำนวนที่นับได้ครั้งเดียว


ทำไมต้องใช้ Linq มันจะเร็วกว่าการใช้รายการและส่วนเสริมหรือไม่
ThunderGr

1
ฉันไม่รู้ว่าอะไรจะเร็วขึ้นและไม่คิดว่ามันเป็นคำถามที่สำคัญ สำหรับสถานที่ใดก็ตามที่คุณใช้รหัสนี้สำหรับการแก้ไขปัญหานี้ความแตกต่างของประสิทธิภาพจะไม่มีความสำคัญ คำถามควรเป็นสิ่งที่อ่านง่ายขึ้นเพื่อความง่ายในการบำรุงรักษาของรหัสในอนาคต ฉันคิดว่านี่เป็นคำตอบที่สมเหตุสมผลเพราะมันใส่ไว้ในบรรทัดซอร์สเดียวซึ่งฉันคิดว่าเป็นส่วนหนึ่งของคำถามที่ต้องการการโทรที่จำเป็นและแสดงเจตนาของบรรทัดนั้นอย่างชัดเจน list และ addrange นั้นเบี่ยงเบนความสนใจไปหลายขั้นตอนเพื่อให้ได้สิ่งเดียวกัน
Dave Rael

7

Nope ลองทำสิ่งต่อไปนี้:

List<string> _searchPatternList = new List<string>();
    ...
    List<string> fileList = new List<string>();
    foreach ( string ext in _searchPatternList )
    {
        foreach ( string subFile in Directory.GetFiles( folderName, ext  )
        {
            fileList.Add( subFile );
        }
    }

    // Sort alpabetically
    fileList.Sort();

    // Add files to the file browser control    
    foreach ( string fileName in fileList )
    {
        ...;
    }

นำมาจาก: http://blogs.msdn.com/markda/archive/2006/04/20/580075.aspx


7

ปล่อย

var set = new HashSet<string> { ".mp3", ".jpg" };

แล้วก็

Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
         .Where(f => set.Contains(
             new FileInfo(f).Extension,
             StringComparer.OrdinalIgnoreCase));

หรือ

from file in Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
from ext in set
where String.Equals(ext, new FileInfo(file).Extension, StringComparison.OrdinalIgnoreCase)
select file;

getfiles ไม่มี overload u โพสต์
nawfal

5

ฉันไม่สามารถใช้.Whereวิธีการได้เนื่องจากฉันกำลังเขียนโปรแกรมใน. NET Framework 2.0 (Linq รองรับเฉพาะใน. NET Framework 3.5+)

โค้ดด้านล่างไม่สำคัญ case (เพื่อให้.CaBหรือ.cabจะแสดงมากเกินไป)

string[] ext = new string[2] { "*.CAB", "*.MSU" };

foreach (string found in ext)
{
    string[] extracted = Directory.GetFiles("C:\\test", found, System.IO.SearchOption.AllDirectories);

    foreach (string file in extracted)
    {
        Console.WriteLine(file);
    }
}

4

ฟังก์ชั่นต่อไปนี้ค้นหาในหลายรูปแบบคั่นด้วยเครื่องหมายจุลภาค นอกจากนี้คุณยังสามารถระบุการยกเว้นเช่น: "! web.config" จะค้นหาไฟล์ทั้งหมดและยกเว้น "web.config" รูปแบบสามารถผสม

private string[] FindFiles(string directory, string filters, SearchOption searchOption)
{
    if (!Directory.Exists(directory)) return new string[] { };

    var include = (from filter in filters.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) where !string.IsNullOrEmpty(filter.Trim()) select filter.Trim());
    var exclude = (from filter in include where filter.Contains(@"!") select filter);

    include = include.Except(exclude);

    if (include.Count() == 0) include = new string[] { "*" };

    var rxfilters = from filter in exclude select string.Format("^{0}$", filter.Replace("!", "").Replace(".", @"\.").Replace("*", ".*").Replace("?", "."));
    Regex regex = new Regex(string.Join("|", rxfilters.ToArray()));

    List<Thread> workers = new List<Thread>();
    List<string> files = new List<string>();

    foreach (string filter in include)
    {
        Thread worker = new Thread(
            new ThreadStart(
                delegate
                {
                    string[] allfiles = Directory.GetFiles(directory, filter, searchOption);
                    if (exclude.Count() > 0)
                    {
                        lock (files)
                            files.AddRange(allfiles.Where(p => !regex.Match(p).Success));
                    }
                    else
                    {
                        lock (files)
                            files.AddRange(allfiles);
                    }
                }
            ));

        workers.Add(worker);

        worker.Start();
    }

    foreach (Thread worker in workers)
    {
        worker.Join();
    }

    return files.ToArray();

}

การใช้งาน:

foreach (string file in FindFiles(@"D:\628.2.11", @"!*.config, !*.js", SearchOption.AllDirectories))
            {
                Console.WriteLine(file);
            }

4
List<string> FileList = new List<string>();
DirectoryInfo di = new DirectoryInfo("C:\\DirName");

IEnumerable<FileInfo> fileList = di.GetFiles("*.*");

//Create the query
IEnumerable<FileInfo> fileQuery = from file in fileList
                                  where (file.Extension.ToLower() == ".jpg" || file.Extension.ToLower() == ".png")
                                  orderby file.LastWriteTime
                                  select file;

foreach (System.IO.FileInfo fi in fileQuery)
{
    fi.Attributes = FileAttributes.Normal;
    FileList.Add(fi.FullName);
}

file.Extension.ToLower()เป็นการปฏิบัติที่ไม่ดี
abatishchev

ถ้าอย่างนั้นเราควรใช้อะไร? @abatishchev
Nitin Sawant

@Nitin:String.Equals(a, b, StringComparison.OrdinalIgnoreCase)
abatishchev

1
ที่จริงแล้ว file.Extension.Equals (". jpg", StringComparison.OrdinalIgnoreCase) คือสิ่งที่ฉันชอบ ดูเหมือนว่าจะเร็วกว่า. ต่ำกว่าหรือสูงเกินไปหรือดังนั้นพวกเขาจึงพูดทุกที่ที่ฉันค้นหา จริงๆแล้ว. Equal เร็วกว่า == เช่นกันเนื่องจาก == เรียก. Equal และตรวจสอบค่าว่าง (เพราะคุณไม่สามารถทำค่า null ได้ Equal (null))
ThunderGr

4

ใน. NET 2.0 (ไม่มี Linq):

public static List<string> GetFilez(string path, System.IO.SearchOption opt,  params string[] patterns)
{
    List<string> filez = new List<string>();
    foreach (string pattern in patterns)
    {
        filez.AddRange(
            System.IO.Directory.GetFiles(path, pattern, opt)
        );
    }


    // filez.Sort(); // Optional
    return filez; // Optional: .ToArray()
}

จากนั้นใช้:

foreach (string fn in GetFilez(path
                             , System.IO.SearchOption.AllDirectories
                             , "*.xml", "*.xml.rels", "*.rels"))
{}

4
DirectoryInfo directory = new DirectoryInfo(Server.MapPath("~/Contents/"));

//Using Union

FileInfo[] files = directory.GetFiles("*.xlsx")
                            .Union(directory
                            .GetFiles("*.csv"))
                            .ToArray();

3

เพิ่งค้นพบวิธีอื่นในการทำเช่นนั้น ยังไม่ได้ดำเนินการอย่างใดอย่างหนึ่ง แต่โยนมันออกไปเพื่อดูว่าคนอื่นคิดเกี่ยวกับมัน

private void getFiles(string path)
{
    foreach (string s in Array.FindAll(Directory.GetFiles(path, "*", SearchOption.AllDirectories), predicate_FileMatch))
    {
        Debug.Print(s);
    }
}

private bool predicate_FileMatch(string fileName)
{
    if (fileName.EndsWith(".mp3"))
        return true;
    if (fileName.EndsWith(".jpg"))
        return true;
    return false;
}

3

เกี่ยวกับอะไร

string[] filesPNG = Directory.GetFiles(path, "*.png");
string[] filesJPG = Directory.GetFiles(path, "*.jpg");
string[] filesJPEG = Directory.GetFiles(path, "*.jpeg");

int totalArraySizeAll = filesPNG.Length + filesJPG.Length + filesJPEG.Length;
List<string> filesAll = new List<string>(totalArraySizeAll);
filesAll.AddRange(filesPNG);
filesAll.AddRange(filesJPG);
filesAll.AddRange(filesJPEG);

2

สร้างส่วนขยายที่คุณต้องการหนึ่งสตริงเช่น ".mp3.jpg.wma.wmf" แล้วตรวจสอบว่าแต่ละไฟล์มีส่วนขยายที่คุณต้องการหรือไม่ สิ่งนี้ใช้ได้กับ. net 2.0 เนื่องจากไม่ได้ใช้ LINQ

string myExtensions=".jpg.mp3";

string[] files=System.IO.Directory.GetFiles("C:\myfolder");

foreach(string file in files)
{
   if(myExtensions.ToLower().contains(System.IO.Path.GetExtension(s).ToLower()))
   {
      //this file has passed, do something with this file

   }
}

ข้อดีของวิธีนี้คือคุณสามารถเพิ่มหรือลบส่วนขยายโดยไม่ต้องแก้ไขรหัสเช่นเพื่อเพิ่มภาพ png เพียงแค่เขียน myExtensions = ". jpg.mp3.png"


ไม่ทราบว่าคืออะไรs
วงเล็บ

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

ไม่ ... ฉันเชื่อว่าคุณต้องโทรออกมากเท่าที่คุณต้องการ

ฉันจะสร้างฟังก์ชั่นของตัวเองเพื่อรับอาร์เรย์กับสตริงที่มีส่วนขยายที่ฉันต้องการจากนั้นวนซ้ำในอาร์เรย์นั้นเพื่อทำการโทรที่จำเป็นทั้งหมด ฟังก์ชันนั้นจะส่งคืนรายการทั่วไปของไฟล์ที่ตรงกับส่วนขยายที่ฉันส่ง

หวังว่ามันจะช่วย


1

ฉันมีปัญหาเดียวกันและไม่พบวิธีแก้ไขปัญหาที่ถูกต้องดังนั้นฉันจึงเขียนฟังก์ชันชื่อ GetFiles:

/// <summary>
/// Get all files with a specific extension
/// </summary>
/// <param name="extensionsToCompare">string list of all the extensions</param>
/// <param name="Location">string of the location</param>
/// <returns>array of all the files with the specific extensions</returns>
public string[] GetFiles(List<string> extensionsToCompare, string Location)
{
    List<string> files = new List<string>();
    foreach (string file in Directory.GetFiles(Location))
    {
        if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.')+1).ToLower())) files.Add(file);
    }
    files.Sort();
    return files.ToArray();
}

ฟังก์ชั่นนี้จะเรียกDirectory.Getfiles()เพียงครั้งเดียว

ตัวอย่างเช่นเรียกใช้ฟังก์ชันดังนี้:

string[] images = GetFiles(new List<string>{"jpg", "png", "gif"}, "imageFolder");

แก้ไข: หากต้องการรับไฟล์หนึ่งไฟล์ที่มีหลายนามสกุลให้ใช้ไฟล์นี้:

/// <summary>
    /// Get the file with a specific name and extension
    /// </summary>
    /// <param name="filename">the name of the file to find</param>
    /// <param name="extensionsToCompare">string list of all the extensions</param>
    /// <param name="Location">string of the location</param>
    /// <returns>file with the requested filename</returns>
    public string GetFile( string filename, List<string> extensionsToCompare, string Location)
    {
        foreach (string file in Directory.GetFiles(Location))
        {
            if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.') + 1).ToLower()) &&& file.Substring(Location.Length + 1, (file.IndexOf('.') - (Location.Length + 1))).ToLower() == filename) 
                return file;
        }
        return "";
    }

ตัวอย่างเช่นเรียกใช้ฟังก์ชันดังนี้:

string image = GetFile("imagename", new List<string>{"jpg", "png", "gif"}, "imageFolder");

1

ฉันสงสัยว่าทำไมมี "โซลูชั่น" จำนวนมากโพสต์

หากความเข้าใจใหม่ของฉันเกี่ยวกับการทำงานของ GetFiles นั้นถูกต้องมีเพียงสองตัวเลือกเท่านั้นและวิธีการแก้ปัญหาด้านบนสามารถนำมาใช้กับสิ่งเหล่านี้ได้:

  1. GetFiles แล้วตัวกรอง: เร็ว แต่นักฆ่าหน่วยความจำเนื่องจากการจัดเก็บค่าใช้จ่ายจนกว่าตัวกรองจะถูกนำไปใช้

  2. กรองขณะที่ GetFiles: ยิ่งมีการตั้งค่าตัวกรองให้ช้าลง แต่การใช้หน่วยความจำต่ำเนื่องจากไม่มีการจัดเก็บค่าใช้จ่าย
    นี่คือคำอธิบายในโพสต์ด้านบนพร้อมเกณฑ์มาตรฐานที่น่าประทับใจ: ตัวเลือกตัวกรองแต่ละตัวทำให้แยกการดำเนินงาน GetFile เพื่อให้ส่วนเดียวกันของฮาร์ดไดรฟ์อ่านได้หลายครั้ง

ในความคิดของฉันตัวเลือกที่ 1) ดีกว่า แต่การใช้ SearchOption.AllDirectories ในโฟลเดอร์เช่น C: \ จะใช้หน่วยความจำจำนวนมาก
ดังนั้นฉันจะทำวิธีย่อยซ้ำที่ผ่านโฟลเดอร์ย่อยทั้งหมดโดยใช้ตัวเลือก 1)

สิ่งนี้ควรทำให้เกิดเพียง 1 GetFiles-operation ในแต่ละโฟลเดอร์และรวดเร็ว (ตัวเลือก 1) แต่ใช้หน่วยความจำเพียงเล็กน้อยเนื่องจากตัวกรองถูกนำไปใช้หลังการอ่านของโฟลเดอร์ย่อย -> จะถูกลบหลังจากแต่ละโฟลเดอร์ย่อย

โปรดแก้ไขฉันหากฉันผิด ฉันเป็นอย่างที่ฉันบอกว่าค่อนข้างใหม่สำหรับการเขียนโปรแกรม แต่ต้องการที่จะได้รับความเข้าใจที่ลึกซึ้งยิ่งขึ้นของสิ่งต่าง ๆ ที่จะกลายเป็นดีที่ในที่สุด :)


1

หากคุณใช้ VB.NET (หรือนำเข้าการพึ่งพาในโครงการ C # ของคุณ) มีวิธีการอำนวยความสะดวกที่ช่วยกรองหลายนามสกุล:

Microsoft.VisualBasic.FileIO.FileSystem.GetFiles("C:\\path", Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, new string[] {"*.mp3", "*.jpg"});

ใน VB.NET สามารถเข้าถึงได้ผ่าน My-namespace:

My.Computer.FileSystem.GetFiles("C:\path", FileIO.SearchOption.SearchAllSubDirectories, {"*.mp3", "*.jpg"})

น่าเสียดายที่วิธีการอำนวยความสะดวกเหล่านี้ไม่สนับสนุนตัวแปรที่ประเมินอย่างเกียจคร้านเช่นDirectory.EnumerateFiles()นี้


นี่เป็นคำตอบที่ดีที่สุดได้อย่างง่ายดาย แต่ก็มีบางสิ่งที่แฮ็คได้รับการยอมรับ ต้องรักเอ
Robbie Coyne

0

ฉันไม่รู้วิธีแก้ปัญหาที่ดีกว่า แต่ฉันใช้สิ่งนี้:

String[] ext = "*.ext1|*.ext2".Split('|');

            List<String> files = new List<String>();
            foreach (String tmp in ext)
            {
                files.AddRange(Directory.GetFiles(dir, tmp, SearchOption.AllDirectories));
            }

0

นี่เป็นวิธีที่เรียบง่ายและสง่างามในการกรองไฟล์

var allowedFileExtensions = ".csv,.txt";


var files = Directory.EnumerateFiles(@"C:\MyFolder", "*.*", SearchOption.TopDirectoryOnly)
                .Where(s => allowedFileExtensions.IndexOf(Path.GetExtension(s)) > -1).ToArray(); 

-1

หรือคุณสามารถแปลงสตริงของนามสกุลเป็นสตริง ^

vector <string>  extensions = { "*.mp4", "*.avi", "*.flv" };
for (int i = 0; i < extensions.size(); ++i)
{
     String^ ext = gcnew String(extensions[i].c_str());;
     String^ path = "C:\\Users\\Eric\\Videos";
     array<String^>^files = Directory::GetFiles(path,ext);
     Console::WriteLine(ext);
     cout << " " << (files->Length) << endl;
}

2
นี่คือ c ++ ไม่ใช่ c #
วงเล็บ

-1

การใช้รูปแบบการค้นหาของ GetFiles สำหรับการกรองส่วนขยายนั้นไม่ปลอดภัย !! ตัวอย่างเช่นคุณมีไฟล์สองไฟล์ Test1.xls และ Test2.xlsx และคุณต้องการกรองไฟล์ xls โดยใช้รูปแบบการค้นหา * .xls แต่ GetFiles ส่งคืนทั้ง Test1.xls และ Test2.xlsx ฉันไม่ทราบเรื่องนี้และมีข้อผิดพลาดในการผลิต สภาพแวดล้อมเมื่อมีการจัดการไฟล์ชั่วคราวบางไฟล์ในทันใด รูปแบบการค้นหาคือ * .txt และไฟล์ temp ชื่อ * .txt20181028_100753898 ดังนั้นรูปแบบการค้นหาจึงไม่น่าเชื่อถือคุณต้องเพิ่มการตรวจสอบเพิ่มเติมในชื่อไฟล์เช่นกัน


ไม่ตอบคำถาม
Robbie Coyne
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.