写在开头


  今天就放假了,照理说应该写今年的总结了,但是回头一看,很久没有写过技术类的文字了,还是先不吐槽了。

关于文件缓存


  写了很多的代码,常常在写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#之文件缓存的更多相关文章

  1. PHP文件缓存实现

    有些时候,我们不希望使用redis等第三方缓存,使得系统依赖于其他服务.这时候,文件缓存会是一个不错的选择. 我们需要文件缓存实现哪些共更能: 功能实现:get.set.has.increment.d ...

  2. 高性能文件缓存key-value存储—Redis

    1.高性能文件缓存key-value存储-Memcached 2.ASP.NET HttpRuntime.Cache缓存类使用总结 备注:三篇博文结合阅读,简单理解并且使用,如果想深入学习,请多参考文 ...

  3. [Android]异步加载图片,内存缓存,文件缓存,imageview显示图片时增加淡入淡出动画

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3574131.html  这个可以实现ImageView异步加载 ...

  4. php使用文件缓存

    使用php读取mysql中的数据很简单,数据量不大的时候,mysql的性能还是不错的.但是有些查询可能比较耗时,这时可以把查询出的结果,缓存起来,减轻mysql的查询压力. 缓存的方法有几种:使用me ...

  5. 高性能文件缓存key-value存储—Memcached

    1.高性能文件缓存key-value存储—Redis 2.ASP.NET HttpRuntime.Cache缓存类使用总结 备注:三篇博文结合阅读,简单理解并且使用,如果想深入学习,请多参考文章中给出 ...

  6. htaccess 增加静态文件缓存和压缩

    增加图片视频等静态文件缓存: <FilesMatch ".(flv|gif|jpg|jpeg|png|ico|swf)$"> Header set Cache-Cont ...

  7. PHP文件缓存与memcached缓存 相比 优缺点是什么呢【总结】

    如果不考虑其他任何问题,只比较速度的话,那肯定是mem快,但他们各有优缺点.文件缓存优点:1.由于现在的硬盘都非常大,所有如果是大数据的时候,放硬盘里就比较合适,比如做一个cms网站,网站里有10万篇 ...

  8. app缓存设计-文件缓存

    采用缓存,可以进一步大大缓解数据交互的压力,又能提供一定的离线浏览.下边我简略列举一下缓存管理的适用环境: 1. 提供网络服务的应用 2. 数据更新不需要实时更新,哪怕是3-5分钟的延迟也是可以采用缓 ...

  9. phalcon: 缓存片段,文件缓存,memcache缓存

    几种缓存,需要用到前端配置,加后端实例配合着用 片段缓存: public function indexAction() { //渲染页面 $this->view->setTemplateA ...

  10. js和HTML结合(补充知识:如何防止文件缓存的js代码)

    来自<javascript高级程序设计 第三版:作者Nicholas C. Zakas>的学习笔记(二) 使用html标签<script>可以把js嵌入到html页面中,让脚本 ...

随机推荐

  1. Spring框架学习笔记(9)——Spring对JDBC的支持

    一.使用JdbcTemplate和JdbcDaoSupport 1.配置并连接数据库 ①创建项目并添加jar包,要比之前Spring项目多添加两个jar包c3p0-0.9.1.2.jar和mysql- ...

  2. JXLS 2.4.0系列教程(四)——多sheet是怎么做到的

    注:本文代码在第一篇文章基础上修改而成,请务必先阅读第一篇文章. http://www.cnblogs.com/foxlee1024/p/7616987.html 本文也不会过多的讲解模板中遍历表达式 ...

  3. 6.移植uboot-支持yaffs烧写,打补丁

    在上一章,裁剪uboot以及分区后,本章主要使uboot支持yaffs以及制作补丁 1. 修改uboot支持yaffs 首先,每个命令都会对应一个文件,比如nand命令对应的common/cmd_na ...

  4. Lucene学习笔记1(V7.1)

    Lucene是一个搜索类库,solr.nutch和elasticsearch都是基于Lucene.个人感觉学习高级搜索引擎应用程序之前 有必要了解Lucene. 开发环境:idea maven spr ...

  5. Django框架之正则表达式URL误区

    问题:我学习的视频大概是2015年录的,里面用的Django版本比较老关于正则表达式URL这一块都是用的url("url(r'^admin/', admin.site.urls)," ...

  6. struts异常:No result defined for action

    问题描述: No result defined for action com.freedom.funitureCityPSIMS.controller.login.CheckAction and re ...

  7. Spring的RestTemplata使用

    spring-web的RestTemplata是对java底层http的封装,使用RestTemplata用户可以不再关注底层的连接建立,并且RestTemplata不仅支持Rest规范,还可以定义返 ...

  8. Redis跟Spring整合,sentinel模式

    普通模式整合 一.在pom.xml中引入redis的依赖 <dependency> <groupId>org.springframework.data</groupId& ...

  9. CentOS6.x机器安装Azure CLI2.0【1】

    安装Azure CLI 2.0的前提是:机器中必须有 Python 2.7.x 或 Python 3.x.如果机器中没有其中任何一个Python版本,请及时安装 1.准备一台CentOS 6.9的机器 ...

  10. JavaScript 教程:对象

    JavaScript 对象是拥有属性和方法的数据.学过编程语言的都知道,此处不再详述! 1.对象的定义: <script> </script> 对象也可以先创建,再添加属性和属 ...