วิธีค้นหาไฟล์ล่าสุดในไดเรกทอรีที่ใช้. NET และโดยไม่ต้องวนซ้ำ


142

ฉันต้องการค้นหาไฟล์ที่แก้ไขล่าสุดในไดเรกทอรี

ฉันรู้ว่าฉันสามารถวนซ้ำทุกไฟล์ในโฟลเดอร์และเปรียบเทียบFile.GetLastWriteTimeแต่มีวิธีที่ดีกว่าในการทำเช่นนี้โดยไม่ต้องวนซ้ำ?


18
ไม่มีวิธีที่ดีกว่าที่จะหลีกเลี่ยงการวนซ้ำ แม้แต่การใช้ LINQ เพียงแค่ซ่อนการวนซ้ำในฟังก์ชันที่ลึกกว่าซึ่งคุณไม่สามารถมองเห็นได้โดยตรง
Oliver

1
หากคุณต้องการค้นหาไฟล์ที่แก้ไขล่าสุดในระบบไฟล์ทั้งหมดแล้ว NTFS Change Journal จะมีประโยชน์ แม้ว่าจะใช้งานได้ยากมากจาก C #
Ben Voigt

คำตอบ:


318

แล้วอย่างนี้ ...

var directory = new DirectoryInfo("C:\\MyDirectory");
var myFile = (from f in directory.GetFiles()
             orderby f.LastWriteTime descending
             select f).First();

// or...
var myFile = directory.GetFiles()
             .OrderByDescending(f => f.LastWriteTime)
             .First();

84
ส่วนตัวผมพบว่ารุ่นที่ไม่ใช่ sugared ง่ายต่อการอ่าน:directory.GetFiles().OrderByDescending(f => f.LastWriteTime).First()
Jørn Schou-Rode

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

3
ขอบคุณ! ตอนนี้ผมแค่ต้องการที่จะโน้มน้าวให้เจ้านายของฉันเพื่อเร่งกระบวนการของการอัพเกรดเราจาก NET 2.0 เพื่อให้สามารถใช้ Linq :)
คริส Klepeis

3
คุณสามารถใช้ linq กับ 2.0 SP1 กับงานพิเศษเล็ก ๆ น้อย ๆ - เพียงแค่อ้างอิงไฟล์ System.Core.dll จาก 3.5 และตั้งค่าเป็น "คัดลอกภายในเครื่อง"
Scott Ivey

8
ไม่ควรใช้นี้FirstOrDefault()แทนFirst()? หลังจะทำให้InvalidOperationExceptionถ้าไดเรกทอรีว่างเปล่า
โทเบียส J

20

หากคุณต้องการค้นหาซ้ำคุณสามารถใช้รหัสที่สวยงามนี้:

public static FileInfo GetNewestFile(DirectoryInfo directory) {
   return directory.GetFiles()
       .Union(directory.GetDirectories().Select(d => GetNewestFile(d)))
       .OrderByDescending(f => (f == null ? DateTime.MinValue : f.LastWriteTime))
       .FirstOrDefault();                        
}

เพียงเรียกวิธีดังต่อไปนี้:

FileInfo newestFile = GetNewestFile(new DirectoryInfo(@"C:\directory\"));

และนั่นคือมัน ส่งคืนFileInfoอินสแตนซ์หรือnullถ้าไดเรกทอรีว่างเปล่า


12
หรือคุณสามารถใช้ตัวเลือกการค้นหาแบบเรียกซ้ำ
ricksmt

17

ขยายไปยังรูปแรกด้านบนหากคุณต้องการค้นหารูปแบบที่แน่นอนคุณสามารถใช้รหัสต่อไปนี้:

string pattern = "*.txt";
var dirInfo = new DirectoryInfo(directory);
var file = (from f in dirInfo.GetFiles(pattern) orderby f.LastWriteTime descending select f).First();

ฉันต้องการสิ่งนั้น ขอบคุณ.
ashilon

10

รุ่นที่ไม่ใช่ LINQ:

/// <summary>
/// Returns latest writen file from the specified directory.
/// If the directory does not exist or doesn't contain any file, DateTime.MinValue is returned.
/// </summary>
/// <param name="directoryInfo">Path of the directory that needs to be scanned</param>
/// <returns></returns>
private static DateTime GetLatestWriteTimeFromFileInDirectory(DirectoryInfo directoryInfo)
{
    if (directoryInfo == null || !directoryInfo.Exists)
        return DateTime.MinValue;

    FileInfo[] files = directoryInfo.GetFiles();
    DateTime lastWrite = DateTime.MinValue;

    foreach (FileInfo file in files)
    {
        if (file.LastWriteTime > lastWrite)
        {
            lastWrite = file.LastWriteTime;
        }
    }

    return lastWrite;
}

/// <summary>
/// Returns file's latest writen timestamp from the specified directory.
/// If the directory does not exist or doesn't contain any file, null is returned.
/// </summary>
/// <param name="directoryInfo">Path of the directory that needs to be scanned</param>
/// <returns></returns>
private static FileInfo GetLatestWritenFileFileInDirectory(DirectoryInfo directoryInfo)
{
    if (directoryInfo == null || !directoryInfo.Exists)
        return null;

    FileInfo[] files = directoryInfo.GetFiles();
    DateTime lastWrite = DateTime.MinValue;
    FileInfo lastWritenFile = null;

    foreach (FileInfo file in files)
    {
        if (file.LastWriteTime > lastWrite)
        {
            lastWrite = file.LastWriteTime;
            lastWritenFile = file;
        }
    }
    return lastWritenFile;
}

1
ขออภัยไม่เห็นความจริงที่ว่าคุณไม่ต้องการวนซ้ำ ต่อไป ... บางทีมันอาจจะช่วยให้ใครบางคนค้นหาสิ่งที่คล้ายกัน
TimothyP

3
รหัสนี้ไม่ได้รวบรวม - lastUpdatedFile ไม่ควรเป็นอาร์เรย์ - ค่าเริ่มต้นสำหรับ lastUpdate ไม่ถูกต้อง (0001/0/01)
Lars A. Brekken


3

มันสายไปหน่อย แต่ ...

รหัสของคุณจะไม่ทำงานเพราะlist<FileInfo> lastUpdateFile = null; และหลังจากนั้นlastUpdatedFile.Add(file);ดังนั้นข้อยกเว้น NullReference จะถูกโยนทิ้ง เวอร์ชันการทำงานควรเป็น:

private List<FileInfo> GetLastUpdatedFileInDirectory(DirectoryInfo directoryInfo)
{
    FileInfo[] files = directoryInfo.GetFiles();
    List<FileInfo> lastUpdatedFile = new List<FileInfo>();
    DateTime lastUpdate = DateTime.MinValue;
    foreach (FileInfo file in files)
    {
        if (file.LastAccessTime > lastUpdate)
        {
            lastUpdatedFile.Add(file);
            lastUpdate = file.LastAccessTime;
        }
    }

    return lastUpdatedFile;
}

ขอบคุณ


2

คุณสามารถตอบสนองต่อกิจกรรมไฟล์ใหม่ที่มีFileSystemWatcher


1
ไม่ทำงานเนื่องจากไฟล์สามารถแก้ไขได้ในขณะที่แอปพลิเคชันของเขาไม่ทำงาน
ฟรานซิส B.

1
เขาไม่ได้ให้รายละเอียดแบบนั้น ... เราจะรู้ได้อย่างไรว่ามันไม่ใช่แอพที่ใช้งานได้ยาวนาน
Scott Marlowe

1
เราทำไม่ได้ แต่สกอตต์มีวิธีแก้ปัญหาที่ดีกว่าในทั้งสองกรณี
Badaro

นอกจากนี้โปรดทราบว่า FSW จะไม่ทำงานกับโฟลเดอร์ที่แชร์ในเครือข่ายส่วนใหญ่
bkqc

2

อีกวิธีถ้าคุณใช้Directory.EnumerateFilesและต้องการอ่านไฟล์ที่ถูกแก้ไขล่าสุดโดยอันดับแรก

foreach (string file in Directory.EnumerateFiles(fileDirectory, fileType).OrderByDescending(f => new FileInfo(f).LastWriteTime))

}

1

นี่คือเวอร์ชันที่รับไฟล์ล่าสุดจากแต่ละไดเรกทอรีย่อย

List<string> reports = new List<string>();    
DirectoryInfo directory = new DirectoryInfo(ReportsRoot);
directory.GetFiles("*.xlsx", SearchOption.AllDirectories).GroupBy(fl => fl.DirectoryName)
.ForEach(g => reports.Add(g.OrderByDescending(fi => fi.LastWriteTime).First().FullName));

0
private List<FileInfo> GetLastUpdatedFileInDirectory(DirectoryInfo directoryInfo)
{
    FileInfo[] files = directoryInfo.GetFiles();
    List<FileInfo> lastUpdatedFile = null;
    DateTime lastUpdate = new DateTime(1, 0, 0);
    foreach (FileInfo file in files)
    {
        if (file.LastAccessTime > lastUpdate)
        {
            lastUpdatedFile.Add(file);
            lastUpdate = file.LastAccessTime;
        }
    }

    return lastUpdatedFile;
}

0

ฉันทำสิ่งนี้เป็นกลุ่มแอพของฉันและฉันใช้คำสั่งเช่นนี้:

  var inputDirectory = new DirectoryInfo("\\Directory_Path_here");
  var myFile = inputDirectory.GetFiles().OrderByDescending(f => f.LastWriteTime).First();

จากที่นี่คุณจะมีชื่อไฟล์สำหรับไฟล์ที่บันทึก / เพิ่ม / อัปเดตล่าสุดในไดเรกทอรีของตัวแปร "inputDirectory" ตอนนี้คุณสามารถเข้าถึงได้และทำสิ่งที่คุณต้องการด้วย

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


หากต้องการเพิ่มลงในสิ่งนี้หากเป้าหมายของคุณคือการเรียกคืนพา ธ ของไฟล์และคุณกำลังใช้ FirstOrDefault เนื่องจากอาจเป็นไปได้ว่าไม่มีผลลัพธ์คุณสามารถใช้โอเปอเรเตอร์ที่มีเงื่อนไขบนคุณสมบัติ FullName สิ่งนี้จะทำให้คุณกลับเป็น "null" สำหรับเส้นทางของคุณโดยไม่ต้องบันทึก FileInfo จาก FirstOrDefault ก่อนที่คุณจะเรียกใช้ FullName เส้นทางสตริง = ใหม่ DirectoryInfo (เส้นทาง) .GetFiles () OrderByDescending (o => o.LastWriteTime) .FirstOrDefault ()? FullName;
StalePhish
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.