C#之文件缓存
写在开头
今天就放假了,照理说应该写今年的总结了,但是回头一看,很久没有写过技术类的文字了,还是先不吐槽了。
关于文件缓存
写了很多的代码,常常在写EXE(定时任务)或者写小站点(数据的使用和客户端调用之间)都需要用到缓存,数据在内存和文本都保留一个整体。
当然也可以写到数据库,不过个人觉得不方便查看和管理。(数据量不大)
第一个版本
一般来说,就是一个缓存类,然后存放缓存文件路径,真实数据集合,读写集合,读写文件。
先提供一个公用类
public class TestInfo
{
public string Name { get; set; } public int Age { get; set; } public string Value { get; set; }
}
测试公有类
然后是第一个对文件读写操作的缓存了
public class Cache_Test_1
{
private static List<TestInfo> dataList = new List<TestInfo>(); private static readonly string cachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "cache", "test.txt"); private static readonly string SEP_STR = "---"; static Cache_Test_1()
{
string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "cache");
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
} if (File.Exists(cachePath))
{
string[] lines = File.ReadAllLines(cachePath, Encoding.UTF8);
foreach (var line in lines)
{
string[] lineArray = line.Split(new string[] { SEP_STR }, StringSplitOptions.None);
if (lineArray.Length == )
{
dataList.Add(new TestInfo()
{
Name = lineArray[],
Age = int.Parse(lineArray[]),
Value = lineArray[]
});
}
}
}
} public static void AddInfo(TestInfo info)
{
lock (dataList)
{
var item = dataList.Find(p => p.Name == info.Name);
if (item == null)
{
dataList.Add(info);
}
else
{
item.Age = info.Age;
item.Value = info.Value;
} WriteFile();
}
} public static TestInfo GetInfo(string name)
{
lock (dataList)
{
return dataList.Find(p => p.Name == name);
}
} public static List<TestInfo> GetAll()
{
lock (dataList)
{
return dataList;
}
} private static void WriteFile()
{
StringBuilder content = new StringBuilder();
foreach (var item in dataList)
{
content.AppendLine(item.Name + SEP_STR + item.Age + SEP_STR + item.Value);
} File.WriteAllText(cachePath, content.ToString(), Encoding.UTF8);
}
}
版本1,文件缓存,固定数据格式和类型
但是,这样的操作如果多了起来,问题就出来了。每次写一种缓存就要写一个缓存操作的类了,写着写着,这样的体力活就有点累了,于是
穷则思变,就想,写一个通用一点的吧。于是又了第二个版本
第二个版本
这个版本的目的就是解决重复劳动,见代码
public class Cache_Test_2<T> where T : new()
{
/// <summary>
/// 缓存分隔符
/// </summary>
private static readonly string SEP_STR = "---"; /// <summary>
/// 缓存临时对象集合
/// </summary>
private static List<T> dataList = new List<T>(); /// <summary>
/// 缓存文本路径
/// </summary>
private static string cachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "cache", typeof(T).Name.ToString() + ".txt"); static Cache_Test_2()
{
string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "cache");
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
} if (File.Exists(cachePath))
{
Type t = typeof(T);
string[] lines = File.ReadAllLines(cachePath, Encoding.UTF8);
foreach (var line in lines)
{
string[] lineArray = line.Split(new string[] { SEP_STR }, StringSplitOptions.None);
if (line.Contains(SEP_STR))
{
List<PropertyIndexInfo> list = new List<PropertyIndexInfo>();
T model = new T();
PropertyInfo[] ps = t.GetProperties();
for (int i = ; i < lineArray.Length; i++)
{
var p = ps[i];
if (p.PropertyType == typeof(int))
{
p.SetValue(model, Convert.ToInt32(lineArray[i]), null);
}
else if (p.PropertyType == typeof(string))
{
p.SetValue(model, lineArray[i], null);
}
} dataList.Add(model);
}
}
}
} /// <summary>
/// 新增一个缓存
/// </summary>
/// <param name="t"></param>
public static void Add(T t)
{
lock (dataList)
{
dataList.Add(t); WriteFile();
}
} /// <summary>
/// 读取缓存集合
/// </summary>
/// <returns></returns>
public static List<T> GetAll()
{
lock (dataList)
{
return dataList;
}
} /// <summary>
/// 写入缓存文件(全量)
/// </summary>
private static void WriteFile()
{
StringBuilder content = new StringBuilder();
foreach (var item in dataList)
{
List<string> list = new List<string>();
var ps = typeof(T).GetProperties();
foreach (var p in ps)
{
object p_object = p.GetValue(item, null);
string value = p_object.ToString();
list.Add(value);
} content.AppendLine(string.Join(SEP_STR, list.ToArray()));
} File.WriteAllText(cachePath, content.ToString(), Encoding.UTF8);
}
}
版本2,通用文件缓存(适合一般场景)
虽然,第二个版本出来了,但是大多数时候,我们创建缓存都是在已有的类上面进行操作,不然每次创建缓存可能就需要一个CacheModel这样一个对象了,
这样还有,并不是所有的字段我们都是需要进入缓存文件,这样的情况该如何操作呢,于是我们再次优化了一下代码,出现了目前来说的第三个版本了。
第三个版本
这里,就会新增几个类了,为了解决第二个版本不能解决的问题,当然具体使用还是要看业务场景,因为,更通用就代表更依赖配置了。(代码类)
这里需要几个基本类,用来保存临时管理的。
/// <summary>
/// 特性:指定属性的排序和是否出现在缓存中使用
/// </summary>
public class CacheOrderAttribute : Attribute
{
public int Index { get; set; }
} /// <summary>
/// 对字符串分割的结果的值进行排序
/// </summary>
public class CacheIndexInfo
{
public int Index { get; set; } public string Value { get; set; }
} /// <summary>
/// 对字段的属性进行排序
/// </summary>
public class PropertyIndexInfo
{
public int Index { get; set; } public PropertyInfo PropertyInfo { get; set; }
}
特性和通用缓存用到的类
有了特性,我们就能对单个类的属性进行特性筛查,排序,最终得到我们需要的和不需要的,最开始改好了,楼主测试了一下,速度上还可以,但是数据了一多,
这种每次全部写入文件的方式就low了,于是改成了Append的方式,大大提升了速度。同时添加了一个类,对具体分割的值进行调整的。代码如下:
/// <summary>
/// 文件缓存共有类
/// </summary>
/// <typeparam name="T">类</typeparam>
public class File_Common_Cache<T> where T : new()
{
/// <summary>
/// 缓存分隔符
/// </summary>
private static string SEP_STR = "---"; /// <summary>
/// 缓存临时对象集合
/// </summary>
private static List<T> dataList = new List<T>(); /// <summary>
/// 缓存文本路径
/// </summary>
private static string cachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "cache", typeof(T).Name.ToString() + ".txt"); static File_Common_Cache()
{
string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "cache");
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
} if (File.Exists(cachePath))
{
Type t = typeof(T);
string[] lines = File.ReadAllLines(cachePath, Encoding.UTF8);
foreach (var line in lines)
{
string[] lineArray = line.Split(new string[] { SEP_STR }, StringSplitOptions.None);
if (line.Contains(SEP_STR))
{
List<PropertyIndexInfo> list = new List<PropertyIndexInfo>();
T model = new T();
PropertyInfo[] ps = t.GetProperties();
foreach (var p in ps)
{
var ads = p.GetCustomAttributesData();
if (ads.Count > )
{
int index = Convert.ToInt32(ads[].NamedArguments[].TypedValue.Value);
list.Add(new PropertyIndexInfo() { Index = index, PropertyInfo = p });
}
} list = list.OrderBy(p => p.Index).ToList();
for (int i = ; i < list.Count; i++)
{
var pt = list[i].PropertyInfo.PropertyType;
if (pt == typeof(int))
{
list[i].PropertyInfo.SetValue(model, Convert.ToInt32(lineArray[i]), null);
}
else if (pt == typeof(string))
{
list[i].PropertyInfo.SetValue(model, lineArray[i], null);
}
else if (pt == typeof(DateTime))
{
list[i].PropertyInfo.SetValue(model, Convert.ToDateTime(lineArray[i]), null);
}
else
{
try
{
list[i].PropertyInfo.SetValue(model, (object)lineArray[i], null);
}
catch
{
throw new Exception("不支持属性类型(仅支持,int,string,DateTime,object)");
}
}
} dataList.Add(model);
}
}
}
} /// <summary>
/// 初始化配置(修改默认分割和保存文件使用)
/// </summary>
/// <param name="sep_str">分隔符</param>
/// <param name="fileName">缓存文件名</param>
public static void InitSet(string sep_str, string fileName)
{
SEP_STR = sep_str;
cachePath = fileName;
} /// <summary>
/// 新增一个缓存
/// </summary>
/// <param name="t"></param>
public static void Add(T t)
{
lock (dataList)
{
dataList.Add(t); AppendFile(t);
}
} /// <summary>
/// 移除一个缓存
/// </summary>
/// <param name="t"></param>
public static void Remove(T t)
{ } /// <summary>
/// 读取缓存集合
/// </summary>
/// <returns></returns>
public static List<T> GetAll()
{
lock (dataList)
{
return dataList;
}
} /// <summary>
/// 写入缓存文件(全量)
/// </summary>
private static void WriteFile()
{
StringBuilder content = new StringBuilder();
foreach (var item in dataList)
{
List<CacheIndexInfo> list = new List<CacheIndexInfo>();
var ps = typeof(T).GetProperties();
foreach (var p in ps)
{
var ads = p.GetCustomAttributesData();
if (ads.Count > )
{
int index = Convert.ToInt32(ads[].NamedArguments[].TypedValue.Value);
object p_object = p.GetValue(item, null);
string value = string.Empty;
if (p.PropertyType == typeof(DateTime))
{
value = p_object == null ? DateTime.Parse("1900-1-1").ToString("yyyy-MM-dd HH:mm:ss") :
Convert.ToDateTime(p_object).ToString("yyyy-MM-dd HH:mm:ss");
}
else
{
value = p_object == null ? "" : p_object.ToString();
} list.Add(new CacheIndexInfo() { Index = index, Value = value });
}
} list = list.OrderBy(a => a.Index).ToList();
content.AppendLine(string.Join(SEP_STR, (from f in list select f.Value).ToArray()));
} File.WriteAllText(cachePath, content.ToString(), Encoding.UTF8);
} /// <summary>
/// 写入缓存文件(附加)
/// </summary>
/// <param name="t"></param>
private static void AppendFile(T t)
{
StringBuilder content = new StringBuilder();
List<CacheIndexInfo> list = new List<CacheIndexInfo>();
var ps = typeof(T).GetProperties();
foreach (var p in ps)
{
var ads = p.GetCustomAttributesData();
if (ads.Count > )
{
int index = Convert.ToInt32(ads[].NamedArguments[].TypedValue.Value);
object p_object = p.GetValue(t, null);
string value = string.Empty;
if (p.PropertyType == typeof(DateTime))
{
value = p_object == null ? DateTime.Parse("1900-1-1").ToString("yyyy-MM-dd HH:mm:ss") :
Convert.ToDateTime(p_object).ToString("yyyy-MM-dd HH:mm:ss");
}
else
{
value = p_object == null ? "" : p_object.ToString();
} list.Add(new CacheIndexInfo() { Index = index, Value = value });
}
} list = list.OrderBy(a => a.Index).ToList();
content.AppendLine(string.Join(SEP_STR, (from f in list select f.Value).ToArray()));
File.AppendAllText(cachePath, content.ToString(), Encoding.UTF8);
}
}
终版(文件缓存类)
测试代码
class Program
{
static void Main(string[] args)
{
TInfo info = new TInfo();
info.Name = "test";
info.Age = ;
info.Test = "我是测试字符串";
var list = File_Common_Cache<TInfo>.GetAll();
DateTime startTime = DateTime.Now;
for (int i = ; i < ; i++)
{
File_Common_Cache<TInfo>.Add(info);
} TimeSpan span = DateTime.Now - startTime;
Console.WriteLine(span.TotalMilliseconds);
Console.ReadLine();
}
} public class TInfo
{
[CacheOrder(Index = )]
public string Name { get; set; } [CacheOrder(Index = )]
public int Age { get; set; } [CacheOrder(Index = )]
public string Test { get; set; }
}
测试代码
测试结果:1秒不到,还是可以。
总结
没啥好总结的,但是不这样写,感觉不规范。写代码的过程中,总是会遇到,写着写着就变成体力活的代码,这个时候,我们就应该认识到问题了,把体力活改变一下,就不再是体力活。
让代码更简单,让生活个多彩。
不足之处,望包含,拍砖,丢鸡蛋。
C#之文件缓存的更多相关文章
- PHP文件缓存实现
有些时候,我们不希望使用redis等第三方缓存,使得系统依赖于其他服务.这时候,文件缓存会是一个不错的选择. 我们需要文件缓存实现哪些共更能: 功能实现:get.set.has.increment.d ...
- 高性能文件缓存key-value存储—Redis
1.高性能文件缓存key-value存储-Memcached 2.ASP.NET HttpRuntime.Cache缓存类使用总结 备注:三篇博文结合阅读,简单理解并且使用,如果想深入学习,请多参考文 ...
- [Android]异步加载图片,内存缓存,文件缓存,imageview显示图片时增加淡入淡出动画
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3574131.html 这个可以实现ImageView异步加载 ...
- php使用文件缓存
使用php读取mysql中的数据很简单,数据量不大的时候,mysql的性能还是不错的.但是有些查询可能比较耗时,这时可以把查询出的结果,缓存起来,减轻mysql的查询压力. 缓存的方法有几种:使用me ...
- 高性能文件缓存key-value存储—Memcached
1.高性能文件缓存key-value存储—Redis 2.ASP.NET HttpRuntime.Cache缓存类使用总结 备注:三篇博文结合阅读,简单理解并且使用,如果想深入学习,请多参考文章中给出 ...
- htaccess 增加静态文件缓存和压缩
增加图片视频等静态文件缓存: <FilesMatch ".(flv|gif|jpg|jpeg|png|ico|swf)$"> Header set Cache-Cont ...
- PHP文件缓存与memcached缓存 相比 优缺点是什么呢【总结】
如果不考虑其他任何问题,只比较速度的话,那肯定是mem快,但他们各有优缺点.文件缓存优点:1.由于现在的硬盘都非常大,所有如果是大数据的时候,放硬盘里就比较合适,比如做一个cms网站,网站里有10万篇 ...
- app缓存设计-文件缓存
采用缓存,可以进一步大大缓解数据交互的压力,又能提供一定的离线浏览.下边我简略列举一下缓存管理的适用环境: 1. 提供网络服务的应用 2. 数据更新不需要实时更新,哪怕是3-5分钟的延迟也是可以采用缓 ...
- phalcon: 缓存片段,文件缓存,memcache缓存
几种缓存,需要用到前端配置,加后端实例配合着用 片段缓存: public function indexAction() { //渲染页面 $this->view->setTemplateA ...
- js和HTML结合(补充知识:如何防止文件缓存的js代码)
来自<javascript高级程序设计 第三版:作者Nicholas C. Zakas>的学习笔记(二) 使用html标签<script>可以把js嵌入到html页面中,让脚本 ...
随机推荐
- [国嵌攻略][136][DM9000网卡驱动深度分析]
网卡初始化 1.分配描述结构,alloc_etherdev 2.获取平台资源,platform_get_resource 2.1.在s3c_dm9k_resource中有相关的资源 2.2.add地址 ...
- ES6中promise的使用方法
先看看ES5中异步编程的使用. let ajax = function (callBlack) { setTimeout(function () { callBlack && call ...
- CSS3技巧巧妙使用:not(:last-of-type)简化你的css代码
终于找到了一个好方法,使用:not(:last-of-type)简单方便,再也不要麻烦的单独使用:last-of-type了,不错! 应用场景:平时我们的列表一般都会有分割线,但是最后一个列表没有分割 ...
- 什么是WEBserver? 经常使用的WEBserver有哪些?
地址:http://www.mamicode.com/ 什么是WEBserver? 经常使用的WEBserver有哪些? 一.什么是WEBserver Webserver能够解析HTTP协议.当Web ...
- 浅谈 C/S 和 B/S 架构
概述 在这个信息急剧膨胀的社会,我们不得不说人类正进入一个崭新的时代,那就是信息时代.信息时代的一个主要而显著的特征就是计算机网络的应用.计算机网络从最初的集中式计算,经过了Client/Server ...
- 解Linux SSH命令大全,新手必看SSH命令
下面介绍一些基本的常用的Linux SSH命令,都是一些很简单的Linux SSH命令,新手掌握了这几个,一般管理一般的vps或者linux主机就可以了! 我们的教程介绍了putty的使用方法 ...
- 利用光场进行深度图估计(Depth Estimation)算法之二——匹配算法
光场相机由于能够捕获相机内部光线的强度和方向而得到整个光场,可以实现重聚焦(refocus)和视角变换等功能.进而可以进行深度估计获取深度图,前面说过利用重聚焦的图像进行深度估计,今天说一下利用不同视 ...
- Tomcat下的Server.xml配置文件详解
自15年毕业到现在已经入行两年多了,一直以来没有深入的了解过tomcat的详细配置,只懂修改一下端口号.在网上找了些相关资料来支撑这篇文章,深入了解server.xml文件各配置的作用 <?xm ...
- xmind2013激活
参考链接:http://blog.163.com/m15999573195_1/blog/static/248705063201542622112823/
- Java通配符解惑
T 有类型 ? 未知类型 一.通配符的上界 既然知道List<Cat>并不是List<Anilmal>的子类型,那就需要去寻找替他解决的办法, 是AnimalTrianer ...