写在开头


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

关于文件缓存


  写了很多的代码,常常在写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. JS使用循环按指定倍数分割数组组成新的数组的方法

    今天一个新人同事问了我一个问题,就是有一个像下边这种不知道具体长度的数组,想以每4个为一组,重新组合为一个二维数组,很简单的需求只需要用到一个循环再去取余数就可以了,写了一个小demo在这里把代码包括 ...

  2. Oracle_group by分组查询_深入

    Oracle_group by分组查询_深入 本文导读:在实际SQL应用中,经常需要进行分组聚合,即将查询对象按一定条件分组,然后对每一个组进行聚合分析.                    创建分 ...

  3. 迈向c++的一次尝试

    从C到C++说着容易做起来也不难,今天做一下尝试. ★:题目介绍:今天是一次尝试所以先从简单的题开始. ★:试题分析:由题可了解到本题目的是要做到由一个数字到一个字符串的转变. 题目简单是由于它只是让 ...

  4. 在Vue项目使用quill-editor带样式编辑器(更改插入图片和视频)

    vue-quill-editor默认插入图片是直接将图片转为base64再放入内容中,如果图片比较大的话,富文本的内容就会很大. 插入视频是直接弹框输入URL地址,某些需求下我们需要让用户去本地选择自 ...

  5. C#编写影院售票系统(A project with a higher amount of gold )(2:相关代码)

    此篇文章为项目代码,,,需要项目需求 ,思路分析与窗体效果请访问:http://www.cnblogs.com/lsy131479/p/8367304.html 项目类图: 影院类: using Sy ...

  6. 进程间通信之利用CreateFilemapping()

    这两天在复习进程间通信,复习一下记不住,复习一下记不住...就写个小博客献个丑,先来第一个内存映射 代码亲测通过 CreateFileMapping()的最后的一位用来做进程间通信 步骤: 1.Cre ...

  7. linux tpm 测试完整记录,亲测有效。

    没有tpm芯片,采用模拟器的方式来测试. 实验环境:内核版本 3.10.0-327 软件包准备: 内网,没有仓库,自己网上下载: 1. cmake-3.9.6-Linux-x86_64.tar.gz ...

  8. mysql 存在索引但不能使用索引的典型场景

    mysql 演示数据库:http://downloads.mysql.com/docs/sakila-db.zip 以%开头的LIKE查询不能够利用B-tree索引 explain select * ...

  9. mysq开启慢查询

    1 将未建立索引的sql放到慢查询日志中 查看 log_queries_not_using_indexes 是否为on show variables like 'log%'; 将 log_querie ...

  10. hibernate 基础

    Hibernate:是开源的ORM框架技术,对jdbc进行了非常轻量级的对象封装,处于业务逻辑层和数据库层之间,称作持久化层. 持久化层的作用:把程序生成的对象持久化到数据库,也就是保存到数据库.   ...