Wie finde ich die neueste Datei in einem Verzeichnis mit .NET und ohne Schleife?

142

Ich muss die zuletzt geänderte Datei in einem Verzeichnis finden.

Ich weiß, dass ich jede Datei in einem Ordner durchlaufen und vergleichen kann File.GetLastWriteTime, aber gibt es eine bessere Möglichkeit, dies ohne Schleifen zu tun?

Chris Klepeis
quelle
18
Nein, es gibt keinen besseren Weg, um Schleifen zu vermeiden. Selbst wenn Sie LINQ verwenden, wird die Schleife nur in eine tiefere Funktionalität ausgeblendet, die Sie nicht direkt sehen können.
Oliver
1
Wenn Sie die zuletzt geänderten Dateien im gesamten Dateisystem suchen möchten, ist das NTFS-Änderungsjournal hilfreich. Sehr, sehr schwer von C # zu verwenden.
Ben Voigt

Antworten:

318

wie wäre es mit so etwas ...

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
quelle
84
Persönlich finde ich, dass die nicht gezuckerte Version leichter zu lesen ist:directory.GetFiles().OrderByDescending(f => f.LastWriteTime).First()
Jørn Schou-Rode
6
Ja, ich stimme auch die meiste Zeit zu - aber wenn ich Beispiele gebe, macht die Abfragesyntax ein bisschen offensichtlicher, dass es sich um eine Linq-Abfrage handelt. Ich werde das Beispiel mit beiden Optionen aktualisieren, um dies zu verdeutlichen.
Scott Ivey
3
Vielen Dank! Jetzt muss ich nur noch meinen Chef davon überzeugen, das Upgrade von .net 2.0 zu beschleunigen, damit ich Linq verwenden kann :)
Chris Klepeis
3
Sie können linq mit 2.0 SP1 mit ein wenig zusätzlicher Arbeit verwenden - verweisen Sie einfach auf die Datei System.Core.dll von 3.5 und setzen Sie sie auf "local kopieren"
Scott Ivey
8
Sollte dies nicht FirstOrDefault()stattdessen verwendet werden First()? Letzteres führt zu einem, InvalidOperationExceptionwenn das Verzeichnis leer ist.
Tobias J
20

Wenn Sie rekursiv suchen möchten, können Sie diesen schönen Code verwenden:

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

Nennen Sie es einfach so:

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

und das ist es. Gibt eine FileInfoInstanz zurück oder nullwenn das Verzeichnis leer ist.

Edgar Villegas Alvarado
quelle
12
Oder Sie können die rekursive Suchoption verwenden .
Ricksmt
17

Wenn Sie das erste Muster oben erweitern möchten, können Sie den folgenden Code verwenden, wenn Sie nach einem bestimmten Muster suchen möchten:

string pattern = "*.txt";
var dirInfo = new DirectoryInfo(directory);
var file = (from f in dirInfo.GetFiles(pattern) orderby f.LastWriteTime descending select f).First();
Zamir
quelle
Ich brauchte das. Danke dir.
Ashilon
10

Eine Nicht-LINQ-Version:

/// <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
quelle
1
Sorry, habe nicht gesehen, dass du keine Schleife machen wolltest. Wie auch immer ... vielleicht hilft es jemandem, etwas Ähnliches zu suchen
TimothyP
3
Dieser Code wird nicht kompiliert. - lastUpdatedFile sollte kein Array sein. - Der Anfangswert für lastUpdate ist ungültig (0001/0/0).
Lars A. Brekken
4

Kurz und einfach :

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

Es ist ein bisschen spät, aber ...

Ihr Code funktioniert aufgrund list<FileInfo> lastUpdateFile = null; und später nicht, lastUpdatedFile.Add(file);sodass eine NullReference-Ausnahme ausgelöst wird. Arbeitsversion sollte sein:

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

Vielen Dank

Oleg Karbushev
quelle
2

Sie können mit FileSystemWatcher auf neue Dateiaktivitäten reagieren .

Scott Marlowe
quelle
1
Es funktioniert nicht, da eine Datei geändert werden kann, während seine Anwendung nicht ausgeführt wird.
Francis B.
1
er hat diese Art von Details nicht angegeben ... Woher wissen wir, dass es keine dauerhafte App ist?
Scott Marlowe
1
Wir nicht, aber Scott hat eine bessere Lösung, was in beiden Fällen funktioniert.
Badaro
Beachten Sie außerdem, dass FSW mit den meisten freigegebenen Netzwerkordnern nicht funktioniert.
bkqc
2

Ein weiterer Ansatz, wenn Sie Directory.EnumerateFilesDateien verwenden und lesen möchten, die zuletzt von first geändert wurden.

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

}
Gaurravs
quelle
1

Hier ist eine Version, die die neueste Datei aus jedem Unterverzeichnis abruft

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
quelle
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
quelle
0

Ich mache das ist eine Reihe meiner Apps und ich benutze eine Aussage wie diese:

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

Von hier aus haben Sie den Dateinamen für die zuletzt gespeicherte / hinzugefügte / aktualisierte Datei im Verzeichnis der Variablen "inputDirectory". Jetzt können Sie darauf zugreifen und damit machen, was Sie wollen.

Hoffentlich hilft das.

JasonR
quelle
Wenn Sie den Dateipfad wiederherstellen möchten und FirstOrDefault verwenden, weil möglicherweise keine Ergebnisse vorliegen, können Sie den nullbedingten Operator für die FullName-Eigenschaft verwenden. Dadurch erhalten Sie für Ihren Pfad "null" zurück, ohne die FileInfo von FirstOrDefault speichern zu müssen, bevor Sie FullName aufrufen. Zeichenfolge path = new DirectoryInfo (Pfad) .GetFiles (). OrderByDescending (o => o.LastWriteTime) .FirstOrDefault ()?. FullName;
StalePhish