I needed a quick file caching solution and here is what I came up with …
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
/// <summary>
/// Provides a file model used by the <see cref="FileCache"/> type.
/// </summary>
public class FileModel
{
/// <summary>
/// Gets or sets information about the file.
/// </summary>
public FileInfo Info { get; set; }
/// <summary>
/// Gets or sets the last time that the file had it's contents cached.
/// </summary>
public DateTime LastUpdate { get; set; }
/// <summary>
/// Gets or sets the file content for the file.
/// </summary>
public StringBuilder Data { get; set; }
}
/// <summary>
/// Provides a caching for file content based on file extensions.
/// </summary>
public class FileCache
{
/// <summary>
/// Holds a singleton instance of a <see cref="FileCache"/> type.
/// </summary>
private static FileCache singleton;
/// <summary>
/// Used to hold the contents of the files.
/// </summary>
private readonly Dictionary<string, FileModel> files;
/// <summary>
/// Holds the list of extensions for files that will have there contents cached.
/// </summary>
private readonly List<string> extensions;
/// <summary>
/// Gets or sets a time value used to determine if a files content should be read again.
/// </summary>
public TimeSpan CacheTime { get; set; }
/// <summary>
/// Gets a list of file extension that will have there contents cached.
/// </summary>
public List<string> Extensions
{
get
{
return this.extensions;
}
}
/// <summary>
/// Default constructor.
/// </summary>
public FileCache()
{
this.files = new Dictionary<string, FileModel>();
this.extensions = new List<string>();
this.extensions.AddRange(new[] { ".htm" });
this.CacheTime = TimeSpan.FromSeconds(2);
}
/// <summary>
/// Provides a helper method for retrieving a file.
/// </summary>
/// <param name="path">The path to the file.</param>
/// <returns>Returns a <see cref="FileModel"/> type containing information about the file.</returns>
public static FileModel GetFile(string path)
{
return Instance.Get(path);
}
/// <summary>
/// Provides a helper method for retrieving a file.
/// </summary>
/// <param name="path">The path to the file.</param>
/// <returns>Returns a <see cref="FileModel"/> type containing information about the file.</returns>
public FileModel Get(string path)
{
// if file does not exit just return null
if (!File.Exists(path))
{
return null;
}
// check if file already exists in the cache
FileModel model;
if (this.files.ContainsKey(path))
{
// get existing entry
model = this.files[path];
}
else
{
// add new entry
model = new FileModel { LastUpdate = DateTime.Now, Info = new FileInfo(path) };
this.files.Add(path, model);
}
// check to cache file data
if (this.extensions.Contains(model.Info.Extension))
{
// not data has been read yet OR (the current time has surpassed the last update time plus the cache time AND
// the current time is greater then the last write time ) we can read the contents of the file
if (model.Data == null || (DateTime.Now > model.LastUpdate + this.CacheTime && DateTime.Now > model.Info.LastWriteTime))
{
model.Data = new StringBuilder(File.ReadAllText(model.Info.FullName));
}
}
// return the modal data
return model;
}
/// <summary>
/// Gets a singleton instance of a <see cref="FileCache"/> type.
/// </summary>
public static FileCache Instance
{
get
{
return singleton ?? (singleton = new FileCache());
}
}
}