Можно ли кэшировать двоичный файл в .NET и выполнять обычные файловые операции с кэшированным файлом?
Кэширование бинарного файла в C#
Ответы (5)
Способ сделать это состоит в том, чтобы прочитать все содержимое из FileStream
в объект MemoryStream
, а затем использовать этот объект для ввода-вывода позже. Оба типа наследуются от Stream
, поэтому использование будет практически идентичным.
Вот пример:
private MemoryStream cachedStream;
public void CacheFile(string fileName)
{
cachedStream = new MemoryStream(File.ReadAllBytes(fileName));
}
Поэтому просто вызовите метод CacheFile
один раз, когда вы хотите кэшировать данный файл, а затем в любом другом месте кода используйте cachedStream
для чтения. (Фактический файл будет закрыт, как только его содержимое будет кэшировано.) Единственное, что нужно помнить, это удалить cachedStream
, когда вы закончите с ним.
Любая современная ОС имеет встроенную систему кэширования, так что фактически всякий раз, когда вы взаимодействуете с файлом, вы взаимодействуете с кешем файла в памяти.
Перед применением пользовательского кэширования необходимо задать важный вопрос: что происходит, когда базовый файл изменяется, и моя кэшированная копия становится недействительной?
Вы можете еще больше усложнить ситуацию, если разрешено изменять кэшированную копию, и эти изменения должны быть сохранены обратно в базовый файл.
Если файл небольшой, проще использовать MemoryStream
, как это предлагается в другом ответе.
Если вам нужно сохранить изменения обратно в файл, вы можете написать класс-оболочку, который перенаправляет все в MemoryStream
, но дополнительно имеет свойство IsDirty, которое устанавливается в значение true всякий раз, когда выполняется операция записи. Тогда у вас может быть некоторый управляющий код, который срабатывает всякий раз, когда вы выберете (в конце какой-то более крупной транзакции?), проверяет наличие (IsDirty == true)
и сохраняет новую версию на диск. Это называется кэшированием «ленивой записи», поскольку изменения выполняются в памяти и фактически не сохраняются до определенного момента.
Если вы действительно хотите все усложнить или у вас очень большой файл, вы можете реализовать свою собственную разбивку по страницам, где вы выбираете размер буфера (может быть, 1 МБ?) и храните небольшое количество byte[]
страниц этого фиксированного размера. На этот раз у вас будет грязный флаг для каждой страницы. Вы бы реализовали методы Stream, чтобы они скрывали детали от вызывающей стороны и извлекали (или отбрасывали) буферы страниц всякий раз, когда это необходимо.
Наконец, если вы хотите облегчить жизнь, попробуйте:
http://www.microsoft.com/Sqlserver/2005/en/us/compact.aspx
Он позволяет вам использовать тот же механизм SQL, что и SQL Server, но в файле, при этом все происходит внутри вашего процесса, а не через внешний сервер СУБД. Это, вероятно, даст вам гораздо более простой способ запроса и обновления вашего файла и избавит вас от необходимости написания большого количества кода сохраняемости от руки.
Ну, вы, конечно, можете прочитать файл в массив byte[] и начать с ним работать. И если вы хотите использовать поток, вы можете скопировать свой FileStream в MemoryStream и начать с ним работать, например:
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 );
}
}
Если вы беспокоитесь о производительности - обычно встроенных механизмов различных методов доступа к файлам должно быть достаточно.
Я не знаю, что именно вы делаете, но я предлагаю это предложение (которое может быть или не быть жизнеспособным в зависимости от того, что вы делаете):
Вместо того, чтобы кэшировать только содержимое файла, почему бы вам не поместить содержимое файла в красивую строго типизированную коллекцию элементов, а затем кэшировать ее? Это, вероятно, сделает поиск элементов немного проще и быстрее, так как не будет синтаксического анализа.
В Lucene есть очень элегантная система кэширования, которая кэширует байты. с диска в память и интеллектуально обновляет хранилище и т. д. Возможно, вы захотите взглянуть на этот код, чтобы понять, как они это делают. Вы также можете прочитать об уровне хранения данных Microsoft SQL Server, так как команда MSSQL довольно откровенно рассказывает о некоторых наиболее важных деталях реализации.