Come trovare il file più recente in una directory usando .NET e senza loop?


142

Devo trovare il file modificato più di recente in una directory.

So che posso scorrere tutti i file in una cartella e confrontarli File.GetLastWriteTime, ma c'è un modo migliore per farlo senza loop ?.


18
No, non esiste un modo migliore per evitare il looping. Anche usando LINQ si nasconde il looping in alcune funzionalità più profonde in cui non è possibile vederlo direttamente.
Oliver,

1
Se si desidera trovare i file modificati più di recente sull'intero filesystem, il journal delle modifiche NTFS sarebbe utile. Molto molto difficile da usare da C #, però.
Ben Voigt,

Risposte:


318

che ne dici di qualcosa del genere...

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
Personalmente, trovo che la versione non zuccherata sia più facile da leggere:directory.GetFiles().OrderByDescending(f => f.LastWriteTime).First()
Jørn Schou-Rode,

6
sì, sono d'accordo anche la maggior parte del tempo, ma quando si danno esempi la sintassi della query rende un po 'più ovvio che si tratta di una query linq. Aggiornerò l'esempio con entrambe le opzioni per chiarire.
Scott Ivey,

3
Grazie! Ora ho solo bisogno di convincere il mio capo ad accelerare il processo di aggiornamento da .net 2.0 in modo da poter usare Linq :)
Chris Klepeis,

3
puoi usare linq con 2.0 SP1 con un po 'di lavoro extra - fai semplicemente riferimento al file System.Core.dll da 3.5 e impostalo su "copia locale"
Scott Ivey,

8
Questo non dovrebbe essere usato al FirstOrDefault()posto di First()? Quest'ultimo causerà un InvalidOperationExceptionse la directory è vuota.
Tobias J,

20

Se vuoi cercare ricorsivamente, puoi usare questo bellissimo pezzo di codice:

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

Basta chiamarlo nel modo seguente:

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

e basta. Restituisce FileInfoun'istanza o nullse la directory è vuota.


12
Oppure puoi usare l' opzione di ricerca ricorsiva .
ricksmt,

17

Espandendo il primo sopra, se si desidera cercare un determinato modello, è possibile utilizzare il seguente codice:

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

Ne avevo bisogno. Grazie.
ashilon,

10

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

1
Spiacente, non ho visto il fatto che non volevi fare il loop. Comunque ... forse aiuterà qualcuno a cercare qualcosa di simile
TimothyP,

3
Questo codice non viene compilato. - lastUpdatedFile non dovrebbe essere un array. - Il valore iniziale per lastUpdate non è valido (0001/0/0).
Lars A. Brekken,

4

Breve e semplice :

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

3

è un po 'tardi ma ...

il tuo codice non funzionerà, a causa list<FileInfo> lastUpdateFile = null; e successivamente lastUpdatedFile.Add(file);verrà generata l'eccezione NullReference. La versione funzionante dovrebbe essere:

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

Grazie


2

È possibile reagire alla nuova attività di file con FileSystemWatcher .


1
Non funziona perché un file può essere modificato mentre la sua applicazione non è in esecuzione.
Francis B.

1
non ha fornito quel tipo di dettaglio ... Come facciamo a sapere che non è un'app persistente?
Scott Marlowe,

1
Noi no, ma Scott ha una soluzione migliore che funziona in entrambi i casi.
Badaro,

Inoltre, tieni presente che FSW non funzionerà con la maggior parte delle cartelle condivise in rete.
bkqc,

2

Un altro approccio se si sta utilizzando Directory.EnumerateFilese si desidera leggere prima i file nell'ultima modifica.

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

}

1

Ecco una versione che ottiene il file più recente da ogni sottodirectory

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

Faccio questo è un sacco di mie app e utilizzo una dichiarazione come questa:

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

Da qui avrai il nome del file salvato / aggiunto / aggiornato più di recente nella directory della variabile "inputDirectory". Ora puoi accedervi e fare quello che vuoi con esso.

Spero che aiuti.


Per aggiungere questo, se il tuo obiettivo è di recuperare il percorso del file e stai usando FirstOrDefault perché è possibile che non ci siano risultati, puoi usare l'operatore null-conditional sulla proprietà FullName. Questo ti restituirà "null" per il tuo percorso senza dover salvare FileInfo da FirstOrDefault prima di chiamare FullName. string path = new DirectoryInfo (path) .GetFiles (). OrderByDescending (o => o.LastWriteTime) .FirstOrDefault () ?. FullName;
StalePhish,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.