C# 小文件缓存 适用并发下载

构思:

     普通的文件下载上传需要反复的进行IO 操作,占用服务器虚拟内存好IO 线程较高,如果控制不好会导致CPU适用率一直占用率过高,本人在项目中遇到该问题,为解决该问题才有以下构思.

     为了解决IO操作频繁IO线程占用过高,采用内存缓存文件(此只能支持较小文件) ,那么采用缓存的时候就要考虑到文件的使用率和内存占用率的问题,为了解决文件使用率过低并占用内存的问题,采用文件使用心跳的检测文件的存活率,并对自定义的缓存器设置文件缓存上限,解决的文件存活率问题那么新的问题来了,如何辨认相同文件,相同文件是否需要缓存两份,因此采用的文件MD5加密获取文件MD5字符串作为缓存键来区分不同文件,那么就可以不需要为相同的两个文件进行分开缓存直接使用同一个缓存就可以了。

那么就有了下列需要完成的功能

     1.缓存器

     2.心跳器+排序(快速排序)

     3.MD5加密

 

     好了有了目标我们就要开始编码,下面进入实现阶段!

 

    1.实现缓存器

          为了实现缓存器就得先构思一下缓存器的结构和成员

          成员1:Hash 表 以作为缓存基础 文中采用 System.Collections.Generic.Dictionary<TKey,TValue> 作为缓存基础

          成员2: 定时器和后台线程实现心跳功能    文中采用 System.Timers.Timer 和  System.ComponentModel.BackgroundWorker

 

 有了大体设计那么我们来细化设计首先细化成员1 Hash表(以下称),基缓存中有TKey和TValue两个属性那么我们根据这两个属性来设计一下缓存项的接口

 鉴于后续的MD5 在此我们将缓存键设计为System.String  类型做为缓存键,然后细化缓存项目的成员

        缓存项接口成员:   

            属性:缓存键、 大小、心跳时间

            方法:刷新缓存 {方法参数: 心跳时间【更新缓存项目最后存活时间】}

            事件:  缓存变更通知事件 【通知缓存器进行操作

 

       实现代码如下:

      枚举:CacheChangedType

CacheChangedType
using System;
using System.Collections.Generic;
using System.Text;

namespace Paabo.Files.Common.Caches.Enumns
{
    /// <summary>
    
/// 缓存改变类型
    
/// </summary>
    
/// <remarks>Paabo,2012-02-10</remarks>
    public enum CacheChangedType
    {
        /// <summary>
        
/// 添加
        
/// </summary>
        Added = 0,
        /// <summary>
        
/// 访问
        
/// </summary>
        Access = 1,
        /// <summary>
        
/// 移除
        
/// </summary>
        Removed = 2
    }
}

     

     自定义委托和委托参数[通知缓存器进行操作]

CacheEvents
using System;
using System.Collections.Generic;
using System.Text;
using Paabo.Files.Common.Caches.Enumns;
using Paabo.Files.Common.Caches.Interfaces;

namespace Paabo.Files.Common.Caches.CommonClass
{
    /// <summary>
    
///  缓存改变委托
    
/// </summary>
    
/// <param name="e">缓存改变委托参数</param>
    
/// <remarks>Paabo,2012-02-10</remarks>
    public delegate void FileCacheChangedEventHandler(FileCacheChangedEventArgs e);

    /// <summary>
    
///  缓存项改变委托
    
/// </summary>
    
/// <param name="e">缓存项改变委托参数</param>
    
/// <remarks>Paabo,2012-02-10</remarks>
    public delegate void CacheItemChangedEventHandler(CacheItemChangedEventArgs e);


    /// <summary>
    
///  缓存改变委托参数
    
/// </summary>
    
/// <remarks>Paabo,2012-02-10</remarks>
    public class FileCacheChangedEventArgs
    {
        #region ====================================  私有字段 ====================================

        private CacheChangedType changedType;

        private ICacheItem item;

        private string itemKey;

        #endregion

        #region ====================================  公共属性 ====================================

        /// <summary>
        
/// 文件MD5值
        
/// </summary>
        public string ItemKey
        {
            get { return itemKey; }
            set { itemKey = value; }
        }

        /// <summary>
        
/// 文件缓存对象
        
/// </summary>
        public ICacheItem Item
        {
            get { return item; }
            set { item = value; }
        }

        /// <summary>
        
/// 缓存变更类型
        
/// </summary>
        public CacheChangedType ChangedType
        {
            get { return changedType; }
            set { changedType = value; }
        }

        #endregion
    }

    /// <summary>
    
/// 缓存项目改变事件参数
    
/// </summary>
    
/// <remarks>Paabo,2012-02-10</remarks>
    public class CacheItemChangedEventArgs
    {

        #region ====================================  私有字段 ====================================

        private string cacheItemKey;

        private DateTime lastAccessDate;

        private CacheChangedType changedType = CacheChangedType.Access;

        #endregion

        #region ====================================  公共属性 ====================================

        /// <summary>
        
/// 缓存项Key
        
/// </summary>
        public string CacheItemKey
        {
            get { return cacheItemKey; }
            set { cacheItemKey = value; }
        }

        /// <summary>
        
/// 缓存项最后活动时间
        
/// </summary>
        public DateTime LastAccessDate
        {
            get { return lastAccessDate; }
            set { lastAccessDate = value; }
        }

        /// <summary>
        
/// 改变类型
        
/// </summary>
        public CacheChangedType ChangedType
        {
            get { return changedType; }
            set { changedType = value; }
        }

        #endregion

        #region ====================================  构造函数 ====================================

        /// <summary>
        
/// 构造函数
        
/// </summary>
        
/// <param name="cacheItemKey">缓存项Key</param>
        
/// <param name="lastAccessDate">最后存活时间</param>
        public CacheItemChangedEventArgs(string cacheItemKey, DateTime lastAccessDate)
        {
            CacheItemKey = cacheItemKey;
            LastAccessDate = lastAccessDate;
        }
        #endregion

    }
}

 

     缓存项 ICacheItem 接口定义

ICacheItem
using System;
using System.Collections.Generic;
using System.Text;
using Paabo.Files.Common.Caches.CommonClass;

namespace Paabo.Files.Common.Caches.Interfaces
{
    /// <summary>
    
/// 缓存项接口
    
/// </summary>
    
/// <remarks>Paabo,2012-02-13</remarks>
    public interface ICacheItem
    {
        /// <summary>
        
/// 缓存大小
        
/// </summary>
        long ItemSize { getset; }

        /// <summary>
        
/// 缓存项键
        
/// </summary>
        string ItemKey { getset; }

        /// <summary>
        
/// 最后存活时间
        
/// </summary>
        DateTime LastAccessDate { getset; }

        /// <summary>
        
/// 刷新缓存
        
/// </summary>
        void RefreshItem(DateTime accessDate);

        /// <summary>
        
/// 缓存项改变通知事件
        
/// </summary>
        event CacheItemChangedEventHandler CacheItemChanged;
    }
}

 

     到此接口定义已经实现,接下来就是实现该接口,接口中包含

属性:

       缓存键     System.String

       大小        System.Long

       心跳时间  System.DateTime

方法:

      更新缓存   参数{心跳时间  System.DateTime}

事件:

      缓存变更通知  CacheItemChangedEventHandler

 

    至此大体上明确,在考虑到以后扩展性方面的问题,我先实现了一个基类 CacheItem 继承于 ICacheItem 简单实现了缓存项接口的属性和方法代码如下

CacheItem

CacheItem
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Paabo.Files.Common.Caches.CommonClass;
using Paabo.Files.Common.Caches.Interfaces;

namespace Paabo.Files.Common.Caches.Items
{
    /// <summary>
    
/// 缓存项基类
    
/// </summary>
    
/// <remarks>Paabo,2012-02-13</remarks>
    public class CacheItem : ICacheItem
    {

        #region ====================================  私有字段 ====================================

        private long itemSize = 0;

        private string itemKey = string.Empty;

        private DateTime lastAccessDate = DateTime.MinValue;

        #endregion

        #region ====================================  公共属性 ====================================

        /// <summary>
        
/// 缓存项大小
        
/// </summary>
        public long ItemSize
        {
            get
            {
                return itemSize;
            }
            set
            {
                itemSize = value;
            }
        }

        /// <summary>
        
/// 缓存键
        
/// </summary>
        public string ItemKey
        {
            get
            {
                return itemKey;
            }
            set
            {
                itemKey = value;
            }
        }

        /// <summary>
        
/// 最后存活时间
        
/// </summary>
        public DateTime LastAccessDate
        {
            get
            {
                return lastAccessDate;
            }
            set
            {
                lastAccessDate = value;
            }
        }

        #endregion

        #region ====================================  自定义事件 ====================================

        /// <summary>
        
/// 缓存项改变事件
        
/// </summary>
        public event CacheItemChangedEventHandler CacheItemChanged;

        #endregion

        #region ====================================  受保护方法 ====================================

        /// <summary>
        
/// 触发缓存项改变
        
/// </summary>
        protected void OnCacheItemChanged()
        {
            if (CacheItemChanged != null)
            {
                CacheItemChanged(new CacheItemChangedEventArgs(this.ItemKey, this.LastAccessDate));
            }
        }

        #endregion

        #region ====================================  公共方法 ====================================

        /// <summary>
        
/// 刷新缓存项目
        
/// </summary>
        
/// <param name="accessDate">访问时间</param>
        public virtual void RefreshItem(DateTime accessDate)
        {
            this.LastAccessDate = accessDate;
            OnCacheItemChanged();
        }

        #endregion
    }
}

 

   到此简单但缓存是够用了但是作为文件缓存还是不够的所以我实现了文件缓存项 ,文件缓存项在缓存项上增加了以下成员

   属性:

         文件名称               System.String

         文件扩展名            System.String 

         文件标题               System.String

         文件内容Byte数组  System.Byte[]

         文件加载类型         枚举

         文件缓存键类型      枚举

   方法:

        加载文件  参数{文件路径,加载类型,缓存键类型}

        读取文件  参数{偏移量,读取长度}

       

    好吧我们结构已经设计好了以后就需要根据结构实现代码:

 

先实现文件缓存项中使用到的两个枚举:

 加载类型

FileLoadType
using System;
using System.Collections.Generic;
using System.Text;

namespace Paabo.Files.Common.Caches.Enumns
{
    /// <summary>
    
/// 文件加载类型
    
/// </summary>
    
/// <remarks>Paabo,2012-02-10</remarks>
    public enum FileLoadType
    {
        /// <summary>
        
/// 不加载
        
/// </summary>
        None = 0,
        /// <summary>
        
/// 加载
        
/// </summary>
        Load = 1,
        /// <summary>
        
/// 延迟加载
        
/// </summary>
        DelayLoad = 2
    }
}

 

缓存键类型

FileKeyType
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Paabo.Files.Common.Caches.Enumns
{
    /// <summary>
    
/// 文件缓存键类型
    
/// </summary>
    
/// <remarks>Paabo,2012-02-13</remarks>
    public enum FileKeyType
    {
        /// <summary>
        
/// 文件MD5值
        
/// </summary>
        MD5=0,
        /// <summary>
        
/// 文件路径
        
/// </summary>
        FilePath =1,
        /// <summary>
        
/// 自定义键
        
/// </summary>
        Custom =2
    }
}

 

然后实现文件缓存项 FileCacheItem:CacheItem,ICacheItem  

具体实现代码如下:

FileCacheItem

FileCacheItem
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Paabo.Files.Common.Caches.Enumns;
using Paabo.Files.Common.Caches.Interfaces;
using Paabo.Files.Common.Caches.CommonClass;

namespace Paabo.Files.Common.Caches.Items
{
    /// <summary>
    
/// 文件缓存项
    
/// </summary>
    
/// <remarks>Paabo,2012-02-10</remarks>
    public class FileCacheItem : CacheItem, ICacheItem
    {
        #region ====================================  私有字段 ====================================

        private byte[] fileBytes;

        private string fileName;

        private string fileExtension;

        private string filePath;

        private FileLoadType loadType = FileLoadType.Load;

        private FileKeyType fileKeyType = FileKeyType.FilePath;

        #endregion

        #region ====================================  公共字段 ====================================


        /// <summary>
        
/// 文件名称
        
/// </summary>
        public string FileName
        {
            get { return fileName; }
            set { fileName = value; }
        }

        /// <summary>
        
/// 文件扩展名
        
/// </summary>
        public string FileExtension
        {
            get { return fileExtension; }
            set { fileExtension = value; }
        }

        /// <summary>
        
/// 文件名称+扩展名
        
/// </summary>
        public string FileTitle
        {
            get
            {
                return FileName + FileExtension;
            }
        }

        /// <summary>
        
/// 文件路径
        
/// </summary>
        public string FilePath
        {
            get { return filePath; }
            set { filePath = value; }
        }


        /// <summary>
        
/// 文件内容
        
/// </summary>
        public byte[] FileBytes
        {
            get { return fileBytes; }
            set { fileBytes = value; }
        }

        /// <summary>
        
/// 加载类型
        
/// </summary>
        public FileLoadType LoadType
        {
            get { return loadType; }
            set { loadType = value; }
        }

        /// <summary>
        
/// 文件缓存键类型
        
/// </summary>
        public FileKeyType FileKeyType
        {
            get { return fileKeyType; }
            set { fileKeyType = value; }
        }

        #endregion

        #region ====================================  构造函数 ====================================

        /// <summary>
        
/// 构造函数
        
/// </summary>
        
/// <param name="filePath">文件路径</param>
        
/// <param name="loadType">加载类型</param>
        public FileCacheItem(string filePath, FileLoadType loadType,FileKeyType fileKeyType)
        {
            loadFile(filePath, loadType, fileKeyType);
        }

        #endregion

        #region ====================================  私有方法 ====================================

        /// <summary>
        
/// 加载文件
        
/// </summary>
        
/// <param name="filePath">文件路径</param>
        
/// <param name="loadType">加载类型</param>
        private void loadFile(string filePath, FileLoadType loadType, FileKeyType fileKeyType)
        {
            if (!File.Exists(filePath))
            {
                throw new ArgumentException("The filePath is not exists !");
            }


            FileInfo info = new FileInfo(filePath);

            this.loadType = loadType;
            this.filePath = filePath;
            this.fileName = Path.GetFileNameWithoutExtension(filePath);
            this.fileExtension = info.Extension;
            this.LastAccessDate = DateTime.Now;
            this.ItemSize = info.Length;
            this.FileKeyType = fileKeyType;
            this.ItemKey = FilePath;

            using (FileStream stream = new FileStream(this.filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                if (FileKeyType == FileKeyType.MD5)
                {
                    this.ItemKey = MD5Helper.GetStreamMD5(stream);
                }

                if (loadType == FileLoadType.Load)
                {
                    this.fileBytes = new Byte[stream.Length];
                    stream.Read(fileBytes, 0, fileBytes.Length);
                }
                stream.Flush();
            }
        }

        #endregion

        #region ====================================  公共方法 ====================================

        /// <summary>
        
/// 读取文件
        
/// </summary>
        
/// <param name="offset">偏移量</param>
        
/// <param name="length">读取长度</param>
        
/// <returns>字符数组</returns>
        public byte[] Read(long offset, long length)
        {
            if (this.FileBytes == null || this.FileBytes.Length < offset + length)
            {
                return null;
            }

            byte[] buffer = new byte[length];

            Array.Copy(this.FileBytes, offset, buffer, 0, length);

            this.LastAccessDate = DateTime.Now;

            OnCacheItemChanged();

            return buffer;
        }

        #endregion
    }
}

 

写到这里我们的的缓存器需要使用的缓存项已经实现,接下来就要实现缓存器中需要使用到的 MD5取文件的MD5值 和 缓存项排序算法

首先我们实现去文件的MD5值辅助类型 命名为MD5Helper 代码如下

  MD5Helper

MD5Helper
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;

namespace Paabo.Files.Common.Caches.CommonClass
{
    /// <summary>
    
/// MD5辅助类
    
/// </summary>
    
/// <remarks>Paabo,2012-02-10</remarks>
    public class MD5Helper
    {
        /// <summary>
        
/// 获取文件MD5值
        
/// </summary>
        
/// <param name="filePath">文件路径</param>
        
/// <returns>文件MD5值</returns>
        public static string GetFileMD5(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new ArgumentNullException("The file is not found !");
            }

            string md5 = string.Empty;

            using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                md5 = GetStreamMD5(stream);
                stream.Flush();
            }


            return md5;
        }

        /// <summary>
        
/// 获取流MD5
        
/// </summary>
        
/// <param name="stream">文件流</param>
        
/// <returns>文件MD5值</returns>
        public static string GetStreamMD5(Stream stream)
        {
            if (stream == null || stream.Length <= 0)
            {
                throw new ArgumentNullException("The stream is null or empty!");
            }


            MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
            byte[] bytes = provider.ComputeHash(stream);

            StringBuilder builder = new StringBuilder(32);

            for (int i = 0; i < bytes.Length; i++)
            {
                builder.Append(bytes[i].ToString("X2"));
            }

            return builder.ToString();
        }
    }
}

 

接着我们实现排序算法 这里实现的是 快速排序 命名为SortHelper 代码如下

SortHelper

SortHelper
using System;
using System.Collections.Generic;
using System.Text;

namespace Paabo.Files.Common.Caches.CommonClass
{
    /// <summary>
    
/// 描述:快速排序
    
/// 作者:Paabo
    
/// 时间:2012-01-17
    
/// </summary>
    public static class SortHelper
    {
        /// <summary>
        
/// 快速排序
        
/// </summary>
        
/// <typeparam name="T">排序类型</typeparam>
        
/// <param name="sources">排序源数组</param>
        
/// <param name="comparison">判定条件</param>
        public static void QuickSort<T>(List<T> sources, Comparison<T> comparison)
        {
            if (sources == null || sources.Count == 0 || sources.Count == 1)
            {
                return;
            }

            QuickSort<T>(sources, 0, sources.Count - 1, comparison);
        }

        /// <summary>
        
/// 快速排序
        
/// </summary>
        
/// <typeparam name="T">排序类型</typeparam>
        
/// <param name="sources">排序源数组</param>
        
/// <param name="low">低位</param>
        
/// <param name="high">高位</param>
        
/// <param name="comparison">判定条件</param>
        private static void QuickSort<T>(List<T> sources, int low, int high, Comparison<T> comparison)
        {
            if (low < high)
            {
                int leftIndex = low;
                int rightIndex = high;

                T item = sources[leftIndex];
                T temp;

                while (leftIndex < rightIndex)
                {
                    while (leftIndex < rightIndex && comparison(sources[leftIndex], item) < 1) { leftIndex++; }
                    while (leftIndex < rightIndex && comparison(sources[rightIndex], item) == 1) { rightIndex--; }

                    if (leftIndex < rightIndex)
                    {
                        temp = sources[leftIndex];
                        sources[leftIndex] = sources[rightIndex];
                        sources[rightIndex] = temp;
                    }
                }

                temp = item;

                int position = comparison(temp, sources[rightIndex]) == -1 ? rightIndex - 1 : rightIndex;
                sources[low] = sources[position];
                sources[position] = temp;

                QuickSort<T>(sources, low, position - 1, comparison);
                QuickSort<T>(sources, position + 1, high, comparison);
            }
        }

        /// <summary>
        
/// 移动指点成员到队列最后
        
/// </summary>
        
/// <typeparam name="TItem">成员类型</typeparam>
        
/// <param name="items">成员数组</param>
        
/// <param name="moveIndex">移动下标</param>
        public static void MoveItemToEnd<TItem>(List<TItem> items, int moveIndex)
        {
            if (items != null && items.Count > 0 && moveIndex < items.Count - 1)
            {
                TItem item = items[moveIndex];

                if (items.Contains(item))
                {
                    items.Remove(item);
                    items.Add(item);
                }
            }
        }

        public static void MoveItemToIndex<TItem>(List<TItem> items, int moveIndex, int toIndex)
        {
            if (toIndex == moveIndex)
            {
                return;
            }


            if (items != null && items.Count > 0 && moveIndex >= 0 && moveIndex < items.Count && toIndex >= 0 && toIndex < items.Count)
            {
                if (toIndex > moveIndex)
                {
                    items.Insert(toIndex + 1, items[moveIndex]);
                    items.RemoveAt(moveIndex);
                }
                else if (toIndex < moveIndex)
                {
                    items.Insert(toIndex, items[moveIndex]);
                    items.RemoveAt(moveIndex + 1);
                }
            }
        }

        
    }
}

 

 到此缓存器需要的成员基本上准备好了,下面设计一下缓存器的结构

字段:

  基缓存

属性:

  缓存键列表

      缓存值列表

      缓存有效时间

      缓存检测时间(心跳检测时间)

      缓存器最大容量

      缓存器当前存储大小

 方法:

  公有

      刷新缓存器设置        参数{缓存器最大容量,缓存有效时间,缓存检测时间}

      检测缓存键是否存在  参数{缓存键}   返回值{是否存在}

      添加缓存                 参数{缓存项}   返回值{缓存键}

      移除缓存                 参数{缓存键}    

      获取缓存                 参数{缓存键}   返回值{缓存项}

 私有

      开始心跳定时器

      停止心跳定时器

      开始检测异步线程

      触发缓存改变通知     参数{缓存改变类型,缓存改变项}

 事件:

      缓存改变通知事件

 

 好吧结构分析完成不废话实现基本没难度就不具体解释直接上代码

 

CustomCache 

 

CustomCache
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Paabo.Files.Common.Caches.Enumns;
using Paabo.Files.Common.Caches.CommonClass;
using Paabo.Files.Common.Caches.Interfaces;
using System.ComponentModel;
using System.Timers;
using System.Threading;

namespace Paabo.Files.Common.Caches.Carrying
{
    /// <summary>
    
/// 文件缓存
    
/// </summary>
    
/// <remarks>Paabo,2012-02-10</remarks>
    public class CustomCache
    {
        #region ====================================  私有字段 ====================================

        /// <summary>
        
/// 有效时长 分钟
        
/// </summary>
        private static int effectiveDate = 1;

        /// <summary>
        
/// 检测间隔
        
/// </summary>
        private static int checkInterval = 10 * 1000;


        /// <summary>
        
/// 是否启动检测定时器
        
/// </summary>
        private static bool isStart = false;

        /// <summary>
        
/// 检测定时器
        
/// </summary>
        private static System.Timers.Timer checkTimer;

        /// <summary>
        
/// 检测后台线程
        
/// </summary>
        private static BackgroundWorker checkWorker;

        /// <summary>
        
/// 文件缓存
        
/// </summary>
        private static Dictionary<string, ICacheItem> caches = new Dictionary<string, ICacheItem>();

        /// <summary>
        
/// 缓存最大大小
        
/// </summary>
        private static long cacheMaxSize = 0;

        /// <summary>
        
/// 当前缓存大小
        
/// </summary>
        private static long currentSize = 0;
        
        /// <summary>
        
/// 缓存Key 的列表
        
/// </summary>
        private static List<string> itemQueue = new List<string>();



        #endregion

        #region ====================================  自定义事件 ====================================

        /// <summary>
        
/// 缓存改变
        
/// </summary>
        public static event FileCacheChangedEventHandler CacheChanged;

        #endregion

        #region ====================================  公共属性 ====================================

        /// <summary>
        
/// 缓存列表
        
/// </summary>
        public static List<ICacheItem> CacheItems
        {
            get
            {
                if (caches == null)
                {
                    return null;
                }

                return new List<ICacheItem>(caches.Values);
            }
        }

        /// <summary>
        
/// 缓存有效时间
        
/// </summary>
        public static int EffectiveDate
        {
            get { return CustomCache.effectiveDate; }
            set { CustomCache.effectiveDate = value; }
        }

        /// <summary>
        
/// 检测间隔 毫秒
        
/// </summary>
        public static int CheckInterval
        {
            get { return CustomCache.checkInterval; }
            set { CustomCache.checkInterval = value; }
        }

        /// <summary>
        
/// 缓存最大容量
        
/// </summary>
        public static long CacheMaxSize
        {
            get { return CustomCache.cacheMaxSize; }
            set { CustomCache.cacheMaxSize = value; }
        }

        /// <summary>
        
/// 当前缓存容量
        
/// </summary>
        public static long CurrentSize
        {
            get { return CustomCache.currentSize; }
            set { CustomCache.currentSize = value; }
        }

        /// <summary>
        
/// 缓存队列
        
/// </summary>
        public static List<string> ItemQueue
        {
            get { return CustomCache.itemQueue; }
            set { CustomCache.itemQueue = value; }
        }

        #endregion

        #region ====================================  公共方法 ====================================

        /// <summary>
        
/// 初始化缓存器
        
/// </summary>
        
/// <param name="maxSize">最大容量</param>
        
/// <param name="effectiveDate">缓存有效时间/分钟</param>
        
/// <param name="checkInterval">缓存检测间隔时间/分钟</param>
        public static void RefreshSetting(int maxSize,int effectiveDate,int checkInterval)
        {
            CacheMaxSize = maxSize * 1024 * 1024;
            EffectiveDate = effectiveDate;
            CheckInterval = checkInterval * 60 * 1000;
        }

        /// <summary>
        
/// 判断缓存是否存在
        
/// </summary>
        
/// <param name="cacheItemKey">缓存键</param>
        
/// <returns></returns>
        public static bool ContainsKey(string cacheItemKey)
        {
            if (caches == null || caches.Count <= 0)
            {
                return false;
            }

            return caches.ContainsKey(cacheItemKey);
        }

        /// <summary>
        
/// 添加缓存
        
/// </summary>
        
/// <param name="filePath">文件路径</param>
        
/// <returns>文件MD5</returns>
        public static string Add<TCacheItem>(TCacheItem item) where TCacheItem : ICacheItem
        {
            if (item == null)
            {
                return string.Empty;
            }
            if (caches.ContainsKey(item.ItemKey))
            {
                caches[item.ItemKey].RefreshItem(DateTime.Now);
            }
            else
            {
                caches[item.ItemKey] = item;

                item.CacheItemChanged += new CacheItemChangedEventHandler(item_CacheItemChanged);

                CurrentSize += item.ItemSize;

                startTimer();

                if (currentSize >= CacheMaxSize)
                {
                    startCheckWorker();
                }

                onCacheChanged(CacheChangedType.Added, item);
            }

            if (!itemQueue.Contains(item.ItemKey))
            {
                itemQueue.Add(item.ItemKey);
            }

            return item.ItemKey;
        }

        /// <summary>
        
/// 获取缓存
        
/// </summary>
        
/// <typeparam name="TCacheItem">缓存类型</typeparam>
        
/// <param name="cacheItemKey">缓存键</param>
        
/// <returns></returns>
        public static TCacheItem GetItme<TCacheItem>(string cacheItemKey) where TCacheItem : ICacheItem
        {
            if (caches.ContainsKey(cacheItemKey))
            {
                return (TCacheItem)caches[cacheItemKey];
            }

            return default(TCacheItem);
        }

        /// <summary>
        
/// 移除文件缓存
        
/// </summary>
        
/// <param name="cacheItemKey"></param>
        public static void Remove(string cacheItemKey)
        {
            if (caches != null && caches.ContainsKey(cacheItemKey))
            {
                lock (caches)
                {
                    ICacheItem item = caches[cacheItemKey];

                    caches.Remove(cacheItemKey);
                    CurrentSize -= item.ItemSize;
                    if (itemQueue.Contains(cacheItemKey))
                    {
                        itemQueue.Remove(cacheItemKey);
                    }
                    onCacheChanged(CacheChangedType.Added, item);
                }
            }
        }

        #endregion

        #region ====================================  私有方法 ====================================

        /// <summary>
        
/// 启动检测定时器
        
/// </summary>
        private static void startTimer()
        {
            if (checkTimer == null || !checkTimer.Enabled)
            {
                if (checkTimer == null)
                {
                    checkTimer = new System.Timers.Timer();
                    checkTimer.Elapsed += new ElapsedEventHandler(checkCache);
                }

                if (!checkTimer.Enabled)
                {
                    checkTimer.Enabled = true;
                    checkTimer.Interval = checkInterval;
                }

            }

            if (!isStart)
            {
                checkTimer.Start();
                isStart = true;
            }
        }

        /// <summary>
        
/// 定时检测
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private static void checkCache(object sender, ElapsedEventArgs e)
        {
            if (caches == null || caches.Count == 0)
            {
                checkTimer.Stop();
                return;
            }

            stopTimer();

            startCheckWorker();

            startTimer();
        }

        /// <summary>
        
/// 启动检测后台线程
        
/// </summary>
        private static void startCheckWorker()
        {
            if (checkWorker == null)
            {
                checkWorker = new BackgroundWorker();
                checkWorker.DoWork += new DoWorkEventHandler(checkWorker_DoWork);
            }

            if (!checkWorker.IsBusy)
            {
                checkWorker.RunWorkerAsync();
            }
        }

        /// <summary>
        
/// 检测后台线程工作单元
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private static void checkWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (caches != null && caches.Count > 0)
            {
                lock (caches)
                {
                    List<ICacheItem> items = new List<ICacheItem>(caches.Values);

                    DateTime now = DateTime.Now;
                    for (int i = 0; i < items.Count; i++)
                    {
                        ICacheItem item = items[i];

                        if (item.LastAccessDate.AddMinutes(effectiveDate) < now)
                        {
                            Remove(item.ItemKey);
                            i--;
                        }
                    }

                    if (caches == null || caches.Count == 0)
                    {
                        stopTimer();
                    }

                    if (CurrentSize > CacheMaxSize)
                    {
                        while (CurrentSize > CacheMaxSize)
                        {
                            string key = itemQueue[0];
                            Remove(key);
                        }
                    }
                }

            }
        }

        /// <summary>
        
/// 停止检测定时器
        
/// </summary>
        private static void stopTimer()
        {
            if (checkTimer != null)
            {
                checkTimer.Enabled = false;
                checkTimer.Stop();
                isStart = false;
            }
        }

        /// <summary>
        
/// 触发缓存改变
        
/// </summary>
        
/// <param name="type">改变类型</param>
        
/// <param name="item">改变项</param>
        private static void onCacheChanged(CacheChangedType type, ICacheItem item)
        {
            FileCacheChangedEventArgs args = new FileCacheChangedEventArgs();
            if (item != null)
            {
                args.Item = item;
                args.ItemKey = item.ItemKey;
            }
            args.ChangedType = type;

            onCacheChanged(args);
        }

        /// <summary>
        
/// 触发缓存改变事件
        
/// </summary>
        
/// <param name="e">参数</param>
        private static void onCacheChanged(FileCacheChangedEventArgs e)
        {
            if (CacheChanged != null)
            {
                new Thread(args =>
                {
                    try
                    {
                        CacheChanged(e);
                    }
                    catch (Exception ex)
                    {

                    }
                }).Start();
            }
        }

        /// <summary>
        
/// 项改变事件
        
/// </summary>
        
/// <param name="e"></param>
        private static void item_CacheItemChanged(CacheItemChangedEventArgs e)
        {
            if (e.ChangedType == CacheChangedType.Access)
            {
                if (itemQueue.Contains(e.CacheItemKey))
                {
                    int index = itemQueue.IndexOf(e.CacheItemKey);
                    SortHelper.MoveItemToEnd(itemQueue, index);
                    onCacheChanged(CacheChangedType.Access, caches[e.CacheItemKey]);
                }
            }
        }

        #endregion
    }
}


提示使用缓存钱需要先调用    刷新缓存器设置    方法

 

 到此本次文章基本写完,下一篇准备写文件上传下载!

 

各位大牛 老鸟们敬请拍砖,但请勿人身攻击!!!!!!!谢谢!!!!!!!

 

                  

                    ↓↓↓↓↓↓猛击此处获取源码↓↓↓↓↓↓

 

posted @ 2012-03-31 09:28  Paabo  阅读(1386)  评论(1编辑  收藏  举报