Làm cách nào để tìm tệp gần đây nhất trong thư mục bằng .NET và không lặp?


142

Tôi cần tìm tập tin sửa đổi gần đây nhất trong một thư mục.

Tôi biết tôi có thể lặp qua mọi tệp trong một thư mục và so sánh File.GetLastWriteTime, nhưng có cách nào tốt hơn để làm điều này mà không cần lặp không?.


18
Không có cách nào tốt hơn để tránh vòng lặp. Ngay cả khi sử dụng LINQ cũng chỉ ẩn vòng lặp vào một số chức năng sâu hơn mà bạn không thể thấy nó trực tiếp.
Oliver

1
Nếu bạn muốn tìm (các) tệp được sửa đổi gần đây nhất trên toàn bộ hệ thống tệp, thì Nhật ký thay đổi NTFS sẽ hữu ích. Rất rất khó sử dụng từ C #.
Ben Voigt

Câu trả lời:


318

Còn những thứ như thế này thì sao...

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
Cá nhân, tôi thấy rằng phiên bản không có đường dễ đọc hơn:directory.GetFiles().OrderByDescending(f => f.LastWriteTime).First()
Jørn Schou-Rode

6
vâng, tôi cũng đồng ý hầu hết thời gian - nhưng khi đưa ra ví dụ cú pháp truy vấn làm cho rõ ràng hơn một chút rằng đó là truy vấn linq. Tôi sẽ cập nhật ví dụ với cả hai tùy chọn để làm rõ.
Scott Ivey

3
Cảm ơn! Bây giờ tôi chỉ cần thuyết phục sếp của mình đẩy nhanh quá trình nâng cấp chúng tôi từ .net 2.0 để tôi có thể sử dụng Linq :)
Chris Klepeis 24/07/2012

3
bạn có thể sử dụng linq với 2.0 SP1 với một chút công việc bổ sung - chỉ cần tham khảo tệp System.Core.dll từ 3.5 và đặt thành "sao chép cục bộ"
Scott Ivey

8
Không nên sử dụng FirstOrDefault()thay vì First()? Cái sau sẽ gây ra InvalidOperationExceptionnếu thư mục trống.
Tobias J

20

Nếu bạn muốn tìm kiếm đệ quy, bạn có thể sử dụng đoạn mã đẹp này:

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

Chỉ cần gọi nó theo cách sau:

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

và đó là nó. Trả về một FileInfothể hiện hoặc nullnếu thư mục trống.


12
Hoặc bạn có thể sử dụng tùy chọn tìm kiếm đệ quy .
ricksmt

17

Mở rộng ở mẫu đầu tiên ở trên, nếu bạn muốn tìm kiếm một mẫu nhất định, bạn có thể sử dụng mã sau:

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

Tôi cần điều đó. Cảm ơn bạn.
ashilon

10

Phiên bản không thuộc 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
Xin lỗi, không thấy thực tế là bạn không muốn lặp lại. Dù sao ... có lẽ nó sẽ giúp ai đó tìm kiếm thứ gì đó tương tự
TimothyP

3
Mã này không biên dịch. - lastUpdatedFile không nên là một mảng. - Giá trị ban đầu cho lastUpdate không hợp lệ (0001/0/0).
Lars A. Brekken

4

Ngắn gọn và đơn giản :

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

3

muộn một chút nhưng ...

mã của bạn sẽ không hoạt động, vì list<FileInfo> lastUpdateFile = null; và sau này lastUpdatedFile.Add(file);vì vậy ngoại lệ NullReference sẽ bị ném. Phiên bản làm việc phải là:

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

Cảm ơn


2

Bạn có thể phản ứng với hoạt động tệp mới với FileSystemWatcher .


1
Nó không hoạt động vì một tệp có thể được sửa đổi trong khi ứng dụng của anh ta không chạy.
Phanxicô B.

1
ông đã không đưa ra loại chi tiết đó ... Làm sao chúng ta biết đó không phải là một ứng dụng bền bỉ?
Scott Marlowe

1
Chúng tôi không, nhưng Scott có một giải pháp tốt hơn những gì hoạt động trong cả hai trường hợp.
Badaro

Ngoài ra, lưu ý rằng FSW sẽ không hoạt động với hầu hết các thư mục chia sẻ mạng.
bkqc

2

Một cách tiếp cận khác nếu bạn đang sử dụng Directory.EnumerateFilesvà muốn đọc các tệp trong lần sửa đổi mới nhất trước tiên.

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

}

1

Đây là phiên bản nhận tệp mới nhất từ ​​mỗi thư mục con

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

Tôi làm điều này là một loạt các ứng dụng của tôi và tôi sử dụng một tuyên bố như thế này:

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

Từ đây, bạn sẽ có tên tệp cho tệp được lưu / thêm / cập nhật gần đây nhất trong Danh mục của biến "inputDirectory". Bây giờ bạn có thể truy cập nó và làm những gì bạn muốn với nó.

Mong rằng sẽ giúp.


Để thêm vào điều này, nếu mục tiêu của bạn là lấy lại đường dẫn tệp và bạn đang sử dụng FirstOrDefault vì có thể không có kết quả, bạn có thể sử dụng toán tử có điều kiện null trên thuộc tính FullName. Điều này sẽ trả lại cho bạn "null" cho đường dẫn của bạn mà không phải lưu FileInfo từ FirstOrDefault trước khi bạn gọi FullName. chuỗi path = new DirectoryInfo (path) .GetFiles (). OrderByDesceinating (o => o.LastWriteTime) .irstirstDefDefault ()?. FullName;
StalePhish
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.