【C#】缓存数据

namespace WpfCopy.Controls
{
    public class CacheFileEventArgs : EventArgs
    {
        public bool IsFaulted { get; private set; }
        public CacheFileModel CacheFile { get; private set; }


        public CacheFileEventArgs(CacheFileModel cacheFile)
        {
            CacheFile = cacheFile;
            IsFaulted = false;
        }

        public CacheFileEventArgs()
        {
            IsFaulted = true;
        }

    }


    public class CacheFileModel
    {
        public string RemoteFile { get; set; }
        public string LocalFile { get; set; }

        public DateTime CreateTime { get; set; }
        public DateTime LastUseTime { get; set; }
    }

    class FileCacheMgr
    {
        private const string CacheDir = "CacheFile";

        private const string CacheDataFile = "file.cache";

        /// <summary>
        /// 缓存数据文件的读写锁
        /// </summary>
        readonly object _cacheDataFileLock = new object();

        /// <summary>
        /// 管理缓存数据的锁
        /// </summary>
        readonly object _cacheLock = new object();

        /// <summary>
        /// 缓存数据任务的锁
        /// </summary>
        readonly object _cacheTaskLock = new object();

        /// <summary>
        /// 缓存数据字典
        /// </summary>
        Dictionary<string, CacheFileModel> _cacheDict = new Dictionary<string, CacheFileModel>();

        /// <summary>
        /// 下载任务字典
        /// </summary>
        readonly Dictionary<string, WeakDelegateCollection<CacheFileEventArgs>> _cacheTaskDict = new Dictionary<string, WeakDelegateCollection<CacheFileEventArgs>>();

        private static readonly FileCacheMgr instance = new FileCacheMgr();
        public static FileCacheMgr Instance { get { return instance; } }

        public FileCacheMgr()
        {

        }

        /// <summary>
        /// 读取缓存
        /// </summary>
        void LoadCacheData()
        {
            lock (_cacheDataFileLock)
            {
                if (!File.Exists(CacheDataFile) && Directory.Exists(CacheDir))
                    Directory.Delete(CacheDir, true);
                var xs = new XmlSerializer(typeof(List<CacheFileModel>));
                using (Stream stream = new FileStream(CacheDataFile, FileMode.Open, FileAccess.Read))
                {
                    var list = xs.Deserialize(stream) as List<CacheFileModel> ?? new List<CacheFileModel>();

                    _cacheDict = list.ToDictionary(m => m.RemoteFile);
                }
            }
        }
        /// <summary>
        /// 保存缓存
        /// </summary>
        void SaveCacheData()
        {
            lock (_cacheDataFileLock)
            {
                try
                {
                    var xs = new XmlSerializer(typeof(List<CacheFileModel>));
                    using (Stream stream = new FileStream(CacheDataFile, FileMode.Create, FileAccess.Write))
                    {
                        xs.Serialize(stream, _cacheDict.Values.ToList<CacheFileModel>());
                    }
                }
                catch (Exception)
                {
                    File.Delete(CacheDataFile);
                }
            }
        }
        /// <summary>
        /// 清除过期缓存
        /// </summary>
        public void ClearExpireCache()
        {
            try
            {
                List<string> clearList = new List<string>();

                foreach (var item in _cacheDict)
                {
                    if (DateTime.Now - item.Value.LastUseTime > TimeSpan.FromDays(7))
                        clearList.Add(item.Key);
                }

                foreach (var item in clearList)
                {
                    File.Delete(_cacheDict[item].LocalFile);
                    _cacheDict.Remove(item);
                }

                SaveCacheData();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 添加缓存数据
        /// </summary>
        /// <param name="model"></param>
        public void AddCacheData(CacheFileModel model)
        {
            if (model == null)
                throw new ArgumentException("model");

            lock (_cacheLock)
            {
                if (_cacheDict.ContainsKey(model.RemoteFile) == false)
                {
                    _cacheDict.Add(model.RemoteFile, model);
                    SaveCacheData();
                }
            }
        }
        /// <summary>
        /// 删除缓存文件--
        /// </summary>
        /// <param name="model"></param>
        public void RemoveCacheData(CacheFileModel model)
        {
            if (model == null)
                throw new ArgumentException("model");

            if (File.Exists(model.LocalFile))
                File.Delete(model.LocalFile);

            if (_cacheDict.ContainsKey(model.RemoteFile))
            {
                _cacheDict.Remove(model.RemoteFile);
                SaveCacheData();
            }
        }

        /// <summary>
        /// 获取缓存数据,如果不存在,则创建下载任务
        /// </summary>
        /// <param name="remoteFile"></param>
        /// <param name="callback"></param>
        /// <param name="getFtpFunc"></param>
        void GetCacheFile(string remoteFile, EventHandler<CacheFileEventArgs> callback, Func<MyFtp> getFtpFunc)
        {

            if (_cacheDict.ContainsKey(remoteFile))
            {
                CacheFileModel cache = _cacheDict[remoteFile];
                if (File.Exists(cache.LocalFile))
                {
                    cache.LastUseTime = DateTime.Now;
                    SaveCacheData();

                    if (callback != null)
                    {
                        callback(this, new CacheFileEventArgs(cache));
                    }
                    return;
                }
                else
                {
                    _cacheDict.Remove(remoteFile);
                }
            }

            CreateDownLoadTask(remoteFile, getFtpFunc(), callback);
        }

        void CreateDownLoadTask(string remoteFile, MyFtp myFtp, EventHandler<CacheFileEventArgs> callBack)
        {
            lock (_cacheTaskLock)
            {
                bool exist = _cacheTaskDict.ContainsKey(remoteFile);
                AddCallBackToDictNoLock(remoteFile, callBack);
                if (exist == false)
                {
                    Task.Factory.StartNew(() =>
                    {
                        DownloadFileWork(remoteFile, myFtp, callBack);
                    }, TaskCreationOptions.PreferFairness);
                }
            }
        }

        void DownloadFileWork(string remoteFile, MyFtp myFtp, EventHandler<CacheFileEventArgs> callback)
        {
            string localFile = Path.Combine(CacheDir, Guid.NewGuid().ToString() + Path.GetExtension(remoteFile));

            string path = Path.GetDirectoryName(localFile);

            if (Directory.Exists(path) == false)
            {
                Directory.CreateDirectory(path);
            }
            var eventArgs = new CacheFileEventArgs();
            try
            {
                bool dlRet = myFtp.DownLoad(remoteFile, localFile);
                if (dlRet && File.Exists(localFile))
                {
                    var cacheModel = new CacheFileModel()
                    {
                        RemoteFile = remoteFile,
                        LocalFile = localFile
                    };
                    eventArgs = new CacheFileEventArgs(cacheModel);
                    AddCacheData(cacheModel);
                }
            }
            finally
            {
                try
                {
                    InvokeCallBack(remoteFile, eventArgs);
                }
                finally
                {
                    RemoveCallBack(remoteFile);
                }
            }
        }

        void AddCallBackToDictNoLock(string remoteFile, EventHandler<CacheFileEventArgs> callback)
        {
            if (_cacheTaskDict.ContainsKey(remoteFile) == false)
                _cacheTaskDict.Add(remoteFile, new WeakDelegateCollection<CacheFileEventArgs>());

            var weakEvent = _cacheTaskDict[remoteFile];
            weakEvent.WeakEvent += callback;
        }

        void RemoveCallBack(string remoteFile)
        {
            lock (_cacheTaskLock)
            {
                if (_cacheTaskDict.ContainsKey(remoteFile))
                    _cacheTaskDict.Remove(remoteFile);
            }
        }

        void InvokeCallBack(string remoteFile, CacheFileEventArgs args)
        {
            lock (_cacheTaskLock)
            {
                if (_cacheTaskDict.ContainsKey(remoteFile) == false)
                {
                    return;
                }

                _cacheTaskDict[remoteFile].Invoke(this, args);
            }
        }

    }
}
原文地址:https://www.cnblogs.com/wywnet/p/3990259.html