Bagaimana menemukan file terbaru di direktori menggunakan .NET, dan tanpa perulangan?

142

Saya perlu mencari file yang paling baru dimodifikasi dalam direktori.

Saya tahu saya dapat mengulangi setiap file dalam folder dan membandingkan File.GetLastWriteTime, tetapi apakah ada cara yang lebih baik untuk melakukan ini tanpa mengulang?

Chris Klepeis
sumber
18
Tidak, tidak ada cara yang lebih baik untuk menghindari perulangan. Bahkan menggunakan LINQ hanya menyembunyikan perulangan ke beberapa fungsi yang lebih dalam di mana Anda tidak dapat melihatnya secara langsung.
Oliver
1
Jika Anda ingin menemukan file yang paling baru dimodifikasi pada seluruh sistem file, maka Jurnal Perubahan NTFS akan berguna. Sangat sangat sulit digunakan dari C #.
Ben Voigt

Jawaban:

318

Bagaimana dengan sesuatu yang seperti ini...

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();
Scott Ivey
sumber
84
Secara pribadi, saya menemukan bahwa versi non-gula lebih mudah dibaca:directory.GetFiles().OrderByDescending(f => f.LastWriteTime).First()
Jørn Schou-Rode
6
ya, saya setuju sebagian besar waktu juga - tetapi ketika memberikan contoh sintaks kueri membuatnya sedikit lebih jelas bahwa itu adalah permintaan linq. Saya akan memperbarui contoh dengan kedua opsi untuk memperjelas.
Scott Ivey
3
Terima kasih! Sekarang aku hanya perlu meyakinkan bos saya untuk mempercepat proses upgrade kita dari Net 2.0 sehingga saya dapat menggunakan Linq :)
Chris Klepeis
3
Anda dapat menggunakan LINQ dengan 2.0 SP1 dengan kerja ekstra - hanya referensi file System.Core.dll dari 3,5, dan set ke "copy lokal"
Scott Ivey
8
Tidak harus menggunakan ini FirstOrDefault()bukan First()? Yang terakhir akan menyebabkan InvalidOperationExceptionjika direktori kosong.
Tobias J
20

Jika Anda ingin mencari secara rekursif, Anda dapat menggunakan kode yang indah ini:

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

Sebut saja dengan cara berikut:

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

dan hanya itu. Mengembalikan FileInfocontoh atau nulljika direktori kosong.

Edgar Villegas Alvarado
sumber
12
Atau Anda dapat menggunakan opsi pencarian rekursif .
ricksmt
17

Memperluas yang pertama di atas, jika Anda ingin mencari pola tertentu Anda dapat menggunakan kode berikut:

string pattern = "*.txt";
var dirInfo = new DirectoryInfo(directory);
var file = (from f in dirInfo.GetFiles(pattern) orderby f.LastWriteTime descending select f).First();
Zamir
sumber
Saya membutuhkan itu. Terima kasih.
ashilon
10

Versi non-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;
}
TimothyP
sumber
1
Maaf, tidak melihat kenyataan bahwa Anda tidak ingin mengulang. Bagaimanapun ... mungkin itu akan membantu seseorang mencari sesuatu yang serupa
TimothyP
3
Kode ini tidak dikompilasi. - lastUpdatedFile tidak boleh berupa array. - Nilai awal untuk pemutakhiran terakhir tidak valid (0001/0/0).
Lars A. Brekken
4

Pendek dan sederhana :

new DirectoryInfo(path).GetFiles().OrderByDescending(o => o.LastWriteTime).FirstOrDefault();
Yakub
sumber
3

sudah agak terlambat tapi ...

kode Anda tidak akan berfungsi, karena list<FileInfo> lastUpdateFile = null; dan kemudian lastUpdatedFile.Add(file);pengecualian NullReference akan dibuang. Versi kerja harus:

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;
}

Terima kasih

Oleg Karbushev
sumber
2

Anda dapat bereaksi terhadap aktivitas file baru dengan FileSystemWatcher .

Scott Marlowe
sumber
1
Itu tidak berfungsi karena file dapat dimodifikasi saat aplikasinya tidak berjalan.
Francis B.
1
dia tidak memberikan detail seperti itu ... Bagaimana kita tahu itu bukan aplikasi yang tahan?
Scott Marlowe
1
Kami tidak, tetapi Scott memiliki solusi yang lebih baik apa yang berhasil di kedua kasus.
Badaro
Juga, perhatikan bahwa FSW tidak akan berfungsi dengan sebagian besar folder yang dibagikan jaringan.
bkqc
2

Pendekatan lain jika Anda menggunakan Directory.EnumerateFilesdan ingin membaca file yang termodifikasi terlebih dahulu.

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

}
Gaurrav
sumber
1

Berikut adalah versi yang mendapatkan file terbaru dari setiap subdirektori

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));
Michael Bahig
sumber
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;
}
Sylver1981
sumber
0

Saya melakukan ini adalah sekelompok aplikasi saya dan saya menggunakan pernyataan seperti ini:

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

Dari sini Anda akan memiliki nama file untuk file yang paling baru disimpan / ditambahkan / diperbarui di Direktori variabel "inputDirectory". Sekarang Anda dapat mengaksesnya dan melakukan apa yang Anda inginkan dengannya.

Semoga itu bisa membantu.

JasonR
sumber
Untuk menambahkan ini, jika tujuan Anda adalah untuk mendapatkan kembali jalur file, dan Anda menggunakan FirstOrDefault karena ada kemungkinan bahwa tidak ada hasil, Anda dapat menggunakan operator kondisional nol pada properti FullName. Ini akan mengembalikan Anda kembali "null" untuk jalur Anda tanpa harus menyimpan FileInfo dari FirstOrDefault sebelum Anda memanggil FullName. string path = new DirectoryInfo (path) .GetFiles (). OrderByDescending (o => o.LastWriteTime) .FirstOrDefault () ?. FullName;
StalePhish