2009-05-29 4 views
5

Có thể lưu một tệp nhị phân trong .NET và thực hiện các thao tác tệp bình thường trên tệp được lưu trong bộ nhớ cache không?Caching một tệp nhị phân trong C#

+2

Huh? Bạn có ý nghĩa gì bởi 1) Cache? 2) Tệp nhị phân (ví dụ: Tệp văn bản không, tệp thực thi, hình ảnh)? 3) Hoạt động "Tệp thông thường"? –

+1

Ngoài ra, tại sao bạn muốn lưu vào bộ nhớ cache? Có lẽ nó là không cần thiết? – uriDium

+0

hãy sử dụng trường hợp sử dụng. –

Trả lời

11

Cách thực hiện việc này là đọc toàn bộ nội dung từ FileStream thành đối tượng MemoryStream và sau đó sử dụng đối tượng này cho I/O sau này. Cả hai loại được kế thừa từ Stream, do đó việc sử dụng sẽ có hiệu quả giống hệt nhau.

Dưới đây là một ví dụ:

private MemoryStream cachedStream; 

public void CacheFile(string fileName) 
{ 
    cachedStream = new MemoryStream(File.ReadAllBytes(fileName)); 
} 

Vì vậy, chỉ cần gọi phương pháp CacheFile một lần khi bạn muốn để cache các tập tin nhất định, và sau đó bất cứ nơi nào khác trong mã sử dụng cachedStream cho việc đọc. (Các tập tin thực tế sẽ được đóng lại ngay sau khi nội dung của nó được lưu trữ.) Chỉ có điều cần nhớ là để xử lý cachedStream khi bạn đã kết thúc với nó.

+3

+1: Tôi nghĩ rằng điều này thực sự có thể là những gì người hỏi muốn. –

+0

Nó có thể sẽ ổn - vấn đề duy nhất sẽ là nếu chúng ta đang nói về một tập tin có kích thước của một GB hoặc hai. –

+2

Vâng, phương pháp này tất nhiên không còn hữu ích khi kích thước tệp tiếp cận với bộ nhớ RAM. Đến thời điểm đó, bạn nên sử dụng máy chủ cơ sở dữ liệu, vì vậy tôi cho rằng đây không phải là vấn đề ở đây. – Noldorin

3

Mọi hệ điều hành hiện đại đều có hệ thống bộ nhớ đệm được tích hợp sẵn, vì vậy trên thực tế bất cứ khi nào bạn tương tác với tệp, bạn đang tương tác với bộ nhớ cache trong tệp.

Trước khi áp dụng bộ nhớ đệm tùy chỉnh, bạn cần đặt câu hỏi quan trọng: điều gì sẽ xảy ra khi tệp cơ bản thay đổi, vì vậy bản sao được lưu trong bộ nhớ cache của tôi trở nên không hợp lệ?

Bạn có thể làm phức tạp thêm vấn đề nếu bản sao được lưu trong bộ nhớ cache được phép thay đổi và các thay đổi cần phải được lưu lại vào tệp cơ bản.

Nếu tệp nhỏ, đơn giản chỉ cần sử dụng MemoryStream như được đề xuất trong câu trả lời khác.

Nếu bạn cần lưu thay đổi về tệp, bạn có thể viết lớp bao bọc chuyển tiếp mọi thứ đến MemoryStream, nhưng bổ sung có thuộc tính IsDirty được đặt thành true bất cứ khi nào thao tác ghi được thực hiện. Sau đó, bạn có thể có một số mã quản lý khởi động bất cứ khi nào bạn chọn (ở cuối giao dịch lớn hơn?), Kiểm tra (IsDirty == true) và lưu phiên bản mới vào đĩa. Điều này được gọi là "lười biếng viết" bộ nhớ đệm, như các sửa đổi được thực hiện trong bộ nhớ và không thực sự được lưu cho đến một thời gian sau đó.

Nếu bạn thực sự muốn làm phức tạp vấn đề hoặc bạn có tệp rất lớn, bạn có thể triển khai phân trang của riêng mình, nơi bạn chọn kích thước bộ đệm (có thể là 1 MB?) Và giữ một số nhỏ byte[] trang cố định kích thước. Lần này bạn sẽ có một lá cờ bẩn cho mỗi trang. Bạn sẽ triển khai phương thức Luồng để ẩn các chi tiết từ người gọi và kéo vào (hoặc loại bỏ) các bộ đệm trang bất cứ khi nào cần thiết.

Cuối cùng, nếu bạn muốn có một cuộc sống dễ dàng hơn, hãy thử:

http://www.microsoft.com/Sqlserver/2005/en/us/compact.aspx

Nó cho phép bạn sử dụng công cụ SQL giống như SQL Server nhưng trên một tập tin, với tất cả những gì xảy ra bên trong quá trình của bạn thay vì thông qua một máy chủ RDBMS bên ngoài. Điều này có thể sẽ cung cấp cho bạn một cách đơn giản hơn nhiều để truy vấn và cập nhật tệp của bạn và tránh sự cần thiết phải có nhiều mã lưu giữ bằng tay.

+0

Đó không phải là những gì một tập tin bộ nhớ ánh xạ (http://en.wikipedia.org/wiki/Memory-mapped_file) là? Mặc dù vậy, tôi tink OP muốn đóng tập tin xử lý càng sớm càng tốt. – Noldorin

+0

Ghi nhớ ánh xạ tệp là nơi hệ điều hành sử dụng tệp (do bạn chọn) để cung cấp kho lưu trữ bộ nhớ ảo cho một vùng không gian địa chỉ của quy trình. (Tệp trang phục vụ mục đích này cho bộ nhớ phân bổ bình thường.) Tôi đang nói về thực tế là hệ điều hành có bộ nhớ đệm đĩa hoạt động bất kể cách bạn truy cập tệp. Hãy thử sử dụng grep hoặc tương tự như tìm kiếm vài trăm MB tệp văn bản. Lần thứ hai bạn làm điều đó, nó sẽ xảy ra nhanh hơn rất nhiều và ổ cứng của bạn sẽ không tạo ra âm thanh, bởi vì tất cả trong bộ nhớ. –

+0

@Earwicker: Vâng, tôi chắc chắn bạn đã đúng. Tuy nhiên, sao chép nội dung vào MemoryStream dường như là giải pháp tốt nhất ở đây bởi vì a) nó không duy trì một khóa trên tập tin b) Tôi nghi ngờ nó vẫn sẽ cung cấp lợi ích hiệu suất. – Noldorin

3

Vâng, tất nhiên bạn có thể đọc tệp thành một mảng byte [] và bắt đầu làm việc trên đó. Và nếu bạn muốn sử dụng một dòng bạn có thể sao chép FileStream của bạn thành một MemoryStream và bắt đầu làm việc với nó - như:

public static void CopyStream(Stream input, Stream output) 
{ 
     var buffer = new byte[32768]; 
     int readBytes; 
     while((readBytes = input.Read(buffer, 0, buffer.Length)) > 0) 
     { 
       output.Write(buffer, 0, readBytes); 
     } 
} 

Nếu bạn lo lắng về hiệu suất - tốt, thông thường việc xây dựng các cơ chế của tập tin khác nhau phương pháp truy cập là đủ.

0

Tôi không biết chính xác những gì bạn đang làm, nhưng tôi đưa ra đề nghị này (mà có thể hoặc có thể không khả thi phụ thuộc vào những gì bạn đang làm):

Thay vì chỉ bộ nhớ đệm các nội dung của tập tin, tại sao bạn không đặt nội dung của tập tin trong một bộ sưu tập tốt đẹp của các mặt hàng, và sau đó bộ nhớ cache đó? Nó có thể sẽ giúp tìm kiếm các mục dễ dàng hơn một chút và nhanh hơn vì không có phân tích cú pháp nào liên quan.

+0

tệp chứa nhiều bản ghi. nó thực sự là tập tin nhị phân cơ sở dữ liệu quốc gia maxmind –

+0

từ đó chúng ta có thể giả định rằng vấn đề thực sự là bạn không nhận được hiệu suất bạn muốn từ các truy vấn của bạn? –

0

Có một hệ thống bộ nhớ đệm rất thanh lịch trong Lucene lưu trữ byte từ đĩa vào bộ nhớ và cập nhật thông minh cửa hàng. Bạn có thể muốn xem mã đó để có ý tưởng về cách thực hiện. Bạn cũng có thể muốn đọc trên lớp lưu trữ dữ liệu Microsoft SQL Server - vì nhóm MSSQL khá sắp ra mắt về một số chi tiết triển khai quan trọng hơn.