2009-07-24 14 views
97

Potrzebuję znaleźć ostatnio zmodyfikowany plik w katalogu.Jak znaleźć najnowszy plik w katalogu przy użyciu .NET i bez pętli?

Wiem, że mogę przechodzić przez każdy plik w folderze i porównywać File.GetLastWriteTime, ale czy istnieje lepszy sposób na wykonanie tego bez pętli ?.

+15

No nie ma lepszego sposobu, który pozwala uniknąć pętli. Nawet użycie LINQ powoduje ukrycie pętli w jakiejś głębszej funkcjonalności, w której nie można jej zobaczyć bezpośrednio. – Oliver

+1

Jeśli chcesz znaleźć ostatnio zmodyfikowany plik (y) w całym systemie plików, to przydałby się Dziennik zmian NTFS. Jednak bardzo trudne w użyciu z C#. –

Odpowiedz

220

jak o czymś takim ...

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(); 
+66

Osobiście uważam, że wersja bez cukrzycy jest łatwiejsza do odczytania: 'directory.GetFiles(). OrderByDescending (f => f.LastWriteTime) .First()' –

+5

tak, zgadzam się również przez większość czasu - ale kiedy podając przykłady składni zapytania sprawia, że ​​jest to bardziej oczywiste, że jest to zapytanie linq. Zaktualizuję ten przykład, wyjaśniając obie opcje. –

+3

Dzięki! Teraz muszę przekonać mojego szefa, aby przyspieszył proces uaktualniania nas z .net 2.0, więc mogę użyć Linq :) –

1

Możesz zareagować na nową aktywność pliku przy pomocy FileSystemWatcher.

+1

Nie działa, ponieważ plik można zmodyfikować, gdy jego aplikacja nie jest uruchomiona. –

+1

nie podał tego rodzaju szczegółów ... Skąd wiemy, że to nie jest trwała aplikacja? –

+1

Nie, ale Scott ma lepsze rozwiązanie, które działa w obu przypadkach. – Badaro

9

Non-LINQ wersja:

/// <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

Niestety, nie widziałem, że nie chcesz zapętlać. W każdym razie ... może to pomoże komuś, kto szuka czegoś podobnego. – TimothyP

+3

Ten kod nie jest kompilowany. - lastUpdatedFile nie powinien być tablicą. - Wartość początkowa dla lastUpdate jest nieprawidłowa (0001/0/0). –

18

Jeśli chcesz szukać rekurencyjnie, można użyć tego pięknego kawałka kodu:

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

Wystarczy nazwać to w następujący sposób:

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

i to wszystko. Zwraca instancję FileInfo lub null, jeśli katalog jest pusty.

+8

Lub możesz użyć opcji [wyszukiwanie rekursywne] (http://msdn.microsoft.com/en-us/library/ms143327 (v = vs.110) .aspx). – ricksmt

+2

Ładny kod. to jest naprawdę pomocne. – Monika

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

Niektóre wyjaśnienia byłyby przyjemne, tutaj –

+1

Myślę, że kod jest całkiem jasny i nie potrzebuje żadnych wyjaśnień. – vikasde

14

Rozszerzenie na pierwszym powyżej, jeśli chcesz, aby szukać pewnego wzorca można użyć następującego kodu:

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

Oto wersja, która pobiera najnowszą plik z każdego podkatalogu

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)); 
2

to trochę późno, ale ...

Twój kod nie zadziała, b z powodu list<FileInfo> lastUpdateFile = null; i późniejszego lastUpdatedFile.Add(file);, więc zostanie zgłoszony wyjątek NullReference. wersja robocza powinna być:

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

Dzięki

0

zrobić to grono moich aplikacji i używam oświadczenie takiego:

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

Stąd będziesz miał nazwę pliku ostatnio zapisany/dodany/zaktualizowany plik w katalogu zmiennej "inputDirectory". Teraz możesz uzyskać do niego dostęp i zrobić to, co chcesz.

Nadzieję, że pomaga.

1

Krótkie i proste:

new DirectoryInfo(path).GetFiles().OrderByDescending(o => o.LastWriteTime).FirstOrDefault(); 
Powiązane problemy