2011-10-19 30 views
15

Tôi đang theo dõi một thư mục tệp và độ dài tệp của chúng, ít nhất một trong các tệp này vẫn đang được ghi vào.nhận được chiều dài tệp hiện tại/FileInfo.Lưu trữ bộ nhớ đệm và thông tin cũ

Tôi phải giữ bản ghi cập nhật liên tục của từng độ dài tệp mà tôi sử dụng cho các mục đích khác.

Phương thức Update được gọi sau mỗi 15 giây và cập nhật các thuộc tính của tệp nếu độ dài tệp khác với độ dài được xác định trong bản cập nhật trước.

Phương pháp cập nhật trông giống như sau:

var directoryInfo = new DirectoryInfo(archiveFolder); 
var archiveFiles = directoryInfo.GetFiles() 
           .OrderByDescending(f=>f.CreationTimeUtc); 
foreach (FileInfo fi in archiveFiles) 
{ 
    //check if file existed in previous update already 
    var origFileProps = cachedFiles.GetFileByName(fi.FullName); 
    if (origFileProps != null && fi.Length == origFileProps.EndOffset) 
    { 
     //file length is unchanged 
    } 
    else 
    { 
     //Update the properties of this file 
     //set EndOffset of the file to current file length 
    } 
} 

Tôi nhận thức được thực tế là DirectoryInfo.GetFiles() là di trú trước nhiều FileInfo tài sản bao gồm Length - và đây là ok miễn là không có bộ nhớ đệm được thực hiện giữa các bản cập nhật (thông tin được lưu trong bộ nhớ cache không được quá 15 giây).

Tôi đã theo giả định rằng mỗi DirectoryInfo.GetFiles() gọi tạo ra một tập mới của FileInfos mà tất cả đều được dân cư với thông tin tươi ngay sau đó sử dụng FindFirstFile/FindNextFile Win32 API. Nhưng điều này dường như không đúng.

Rất hiếm khi, nhưng cuối cùng chắc chắn tôi chạy vào các tình huống mà độ dài tệp cho tệp được ghi vào không được cập nhật trong 5, 10 hoặc thậm chí 20 phút mỗi lần (thử nghiệm được thực hiện trên Windows 2008 Server x64 nếu điều đó quan trọng).

Cách giải quyết hiện tại là gọi fi.Refresh() để bắt buộc cập nhật từng thông tin tệp. Nội bộ này dường như ủy quyền cho một cuộc gọi API Win32 GetFileAttributesEx để cập nhật thông tin tệp.

Mặc dù chi phí buộc làm mới theo cách thủ công có thể chấp nhận được Tôi muốn hiểu rõ hơn lý do tại sao Tôi đang nhận được thông tin cũ ngay từ đầu. Khi nào thông tin FileInfo được tạo và nó có liên quan như thế nào với cuộc gọi của DirectoryInfo.GetFiles()? Có một tập tin I/O bộ nhớ đệm lớp bên dưới mà tôi không hoàn toàn nắm bắt?

Trả lời

14

Raymond Chen giờ đây đã viết một bài đăng blog rất chi tiết về chính xác vấn đề này:

Why is the file size reported incorrectly for files that are still being written to?

Trong NTFS, hệ thống tập tin siêu dữ liệu là một tài sản không phải của mục nhập thư mục mà là của tệp, với một số siêu dữ liệu được sao chép vào mục nhập thư mục làm tinh chỉnh để cải thiện điều tra danh bạ hiệu suất. Các hàm như FindFirstFile báo cáo mục nhập và bằng cách đặt siêu dữ liệu mà người dùng FAT đã quen với việc nhận được "miễn phí", họ có thể tránh bị chậm hơn FAT trong danh sách thư mục . Chức năng liệt kê thư mục báo cáo siêu dữ liệu được cập nhật lần cuối, có thể không tương ứng với siêu dữ liệu thực tế nếu mục nhập thư mục cũ.

Về cơ bản nó đi xuống đến hiệu suất: Các thông tin thu thập được từ thư mục DirectoryInfo.GetFiles()FindFirstFile/FindNextFile Win32 API bên dưới được lưu lại để lý do hiệu suất để đảm bảo hiệu suất tốt hơn trong NTFS so với FAT cũ cho thu thập thông tin thư mục. Bạn chỉ có thể lấy thông tin kích thước tệp chính xác bằng cách gọi trực tiếp Get­File­Size() trên tệp trực tiếp (trong .NET gọi Refresh() trên số FileInfo hoặc mua trực tiếp FileInfo từ tên tệp) - hoặc mở và đóng luồng tệp. được truyền đến bộ nhớ cache siêu dữ liệu thư mục. Trường hợp sau giải thích lý do kích thước tệp được cập nhật ngay lập tức khi quá trình ghi đóng tệp.

này cũng giải thích rằng vấn đề dường như không xuất hiện trong Windows 2003 Server - trở lại sau đó các thông tin tập tin được lặp lại thường xuyên hơn/bất cứ khi nào bộ nhớ cache bị xô - đây không phải là trường hợp nữa cho Windows 2008 Server:

Đối với mức độ thường xuyên, câu trả lời phức tạp hơn một chút. Bắt đầu từ Windows Vista (và phiên bản Windows Server tương ứng mà tôi không biết nhưng tôi chắc chắn bạn có thể tra cứu và "you" nghĩa là "Yuhong Bao"), hệ thống tệp NTFS thực hiện điều này nhân rộng khi xử lý cuối cùng đối với một đối tượng tệp được đóng lại. Phiên bản trước của NTFS sao chép dữ liệu trong khi tệp được mở bất cứ khi nào bộ nhớ cache bị xóa, có nghĩa là nó xảy ra thường xuyên theo lịch không thể đoán trước. Kết quả của thay đổi này là mục nhập thư mục hiện được cập nhật ít thường xuyên hơn và do đó, kích thước tệp được cập nhật lần cuối là lỗi thời hơn so với trước đây.

Đọc toàn bộ bài viết rất thông tin và được khuyến nghị!

5

Tôi khuyên bạn nên sử dụng FileSystemWatcher và đăng ký Sự kiện đã thay đổi. Nó được kích hoạt khi mục hệ thống tập tin được chỉ định được thay đổi.

+0

+1 cho đề xuất hợp lý - tại thời điểm này tôi có giải pháp thay thế và trong thời gian dài có nhiều khả năng sẽ tái cấu trúc bằng cách sử dụng FileSystemWatcher - nhưng điều này không trả lời * lý do * Tôi nhận được thông tin cũ câu hỏi này là tất cả về – BrokenGlass

+0

IMO phải có một số lớp tiền mặt hệ điều hành. Ngay cả khi bạn gọi stream.Flush() nó sẽ không buộc tiết kiệm trên HD. Bạn đã cố tắt tính năng ghi bộ nhớ đệm trên đĩa chưa? http://support.microsoft.com/kb/259716 – Wojteq

+0

Khi không có bất kỳ lời giải thích nào khác, tôi sẽ chấp nhận câu trả lời này là giải pháp cho thời gian này. – BrokenGlass

1

Tôi đồng ý với Wojteq rằng việc sử dụng lớp FileSystemWatcher sẽ là giải pháp tốt hơn. Nó cho thấy sự kiện khi các thuộc tính khác nhau của một tệp hoặc thư mục thay đổi (chẳng hạn như sự kiện Thay đổi mà anh ta tham chiếu) và đó là giải pháp tốt hơn so với giải pháp bỏ phiếu hiện đang diễn ra. Để trả lời câu hỏi của bạn về lý do làm mới mất một lượng thời gian để phản ánh sự thay đổi kích thước của tệp, câu trả lời là phải làm với Trình quản lý bộ nhớ ảo bên dưới của hệ điều hành Windows. Khi File I/O được thực hiện, nó thực sự cập nhật các tập tin ánh xạ bộ nhớ; đây là bản sao đệm của tệp được hệ điều hành quản lý. Vì vậy, Windows kiểm soát khi dữ liệu đệm được ghi vào đĩa. Không có cách nào để dự đoán khi nào một phần dữ liệu đệm cụ thể sẽ được ghi vào đĩa. Điều này có nghĩa là việc cập nhật một luồng tập tin sẽ đặt các cập nhật đó vào bộ đệm. Nếu bạn đã Flush() dòng các bản cập nhật đệm nên được ghi vào đĩa ngay lập tức, nếu bạn đóng luồng thì nó sẽ được ghi từ bộ đệm vào đĩa ngay sau khi luồng được đóng, và nếu luồng được giữ mở nó sẽ được mở cho Windows khi nó quyết định ghi dữ liệu đệm vào đĩa.

+0

đệm sẽ giải thích sự chậm trễ cập nhật theo thứ tự giây nhưng không phải phút, mã viết nằm trong C và sử dụng 'fwrite' theo mặc định sử dụng kích thước bộ đệm không quá vài kilo byte AFAIK. – BrokenGlass

+0

+1 Chắc chắn nó có một cái gì đó để làm với các tập tin vẫn đang được ghi vào, tôi nhận thấy tôi nhận được một bản cập nhật chính xác ngay lập tức khi quá trình viết dừng lại. Tuy nhiên, vấn đề thông tin cũ hiếm khi xảy ra, vẫn còn đặt ra câu hỏi * tại sao * điều này xảy ra ngay từ đầu – BrokenGlass

Các vấn đề liên quan