C#之文件缓存

2018-02-12 18:55:41来源:cnblogs.com作者:Supper_litt人点击

分享

写在开头



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


关于文件缓存



  写了很多的代码,常常在写EXE(定时任务)或者写小站点(数据的使用和客户端调用之间)都需要用到缓存,数据在内存和文本都保留一个整体。

当然也可以写到数据库,不过个人觉得不方便查看和管理。(数据量不大)


第一个版本



  一般来说,就是一个缓存类,然后存放缓存文件路径,真实数据集合,读写集合,读写文件。

  先提供一个公用类

1 public class TestInfo2 {3     public string Name { get; set; }4 5     public int Age { get; set; }6 7     public string Value { get; set; }8 }
测试公有类

  然后是第一个对文件读写操作的缓存了

 1 public class Cache_Test_1 2     { 3         private static List<TestInfo> dataList = new List<TestInfo>(); 4  5         private static readonly string cachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "cache", "test.txt"); 6  7         private static readonly string SEP_STR = "---"; 8  9         static Cache_Test_1()10         {11             string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "cache");12             if (!Directory.Exists(dir))13             {14                 Directory.CreateDirectory(dir);15             }16 17             if (File.Exists(cachePath))18             {19                 string[] lines = File.ReadAllLines(cachePath, Encoding.UTF8);20                 foreach (var line in lines)21                 {22                     string[] lineArray = line.Split(new string[] { SEP_STR }, StringSplitOptions.None);23                     if (lineArray.Length == 3)24                     {25                         dataList.Add(new TestInfo()26                         {27                             Name = lineArray[0],28                             Age = int.Parse(lineArray[1]),29                             Value = lineArray[2]30                         });31                     }32                 }33             }34         }35 36         public static void AddInfo(TestInfo info)37         {38             lock (dataList)39             {40                 var item = dataList.Find(p => p.Name == info.Name);41                 if (item == null)42                 {43                     dataList.Add(info);44                 }45                 else46                 {47                     item.Age = info.Age;48                     item.Value = info.Value;49                 }50 51                 WriteFile();52             }53         }54 55         public static TestInfo GetInfo(string name)56         {57             lock (dataList)58             {59                 return dataList.Find(p => p.Name == name);60             }61         }62 63         public static List<TestInfo> GetAll()64         {65             lock (dataList)66             {67                 return dataList;68             }69         }70 71         private static void WriteFile()72         {73             StringBuilder content = new StringBuilder();74             foreach (var item in dataList)75             {76                 content.AppendLine(item.Name + SEP_STR + item.Age + SEP_STR + item.Value);77             }78 79             File.WriteAllText(cachePath, content.ToString(), Encoding.UTF8);80         }81     }
版本1,文件缓存,固定数据格式和类型

  但是,这样的操作如果多了起来,问题就出来了。每次写一种缓存就要写一个缓存操作的类了,写着写着,这样的体力活就有点累了,于是

穷则思变,就想,写一个通用一点的吧。于是又了第二个版本

第二个版本


  这个版本的目的就是解决重复劳动,见代码

  1 public class Cache_Test_2<T> where T : new()  2     {  3         /// <summary>  4         /// 缓存分隔符  5         /// </summary>  6         private static readonly string SEP_STR = "---";  7   8         /// <summary>  9         /// 缓存临时对象集合 10         /// </summary> 11         private static List<T> dataList = new List<T>(); 12  13         /// <summary> 14         /// 缓存文本路径 15         /// </summary> 16         private static string cachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "cache", typeof(T).Name.ToString() + ".txt"); 17  18         static Cache_Test_2() 19         { 20             string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "cache"); 21             if (!Directory.Exists(dir)) 22             { 23                 Directory.CreateDirectory(dir); 24             } 25  26             if (File.Exists(cachePath)) 27             { 28                 Type t = typeof(T); 29                 string[] lines = File.ReadAllLines(cachePath, Encoding.UTF8); 30                 foreach (var line in lines) 31                 { 32                     string[] lineArray = line.Split(new string[] { SEP_STR }, StringSplitOptions.None); 33                     if (line.Contains(SEP_STR)) 34                     { 35                         List<PropertyIndexInfo> list = new List<PropertyIndexInfo>(); 36                         T model = new T(); 37                         PropertyInfo[] ps = t.GetProperties(); 38                         for (int i = 0; i < lineArray.Length; i++) 39                         { 40                             var p = ps[i]; 41                             if (p.PropertyType == typeof(int)) 42                             { 43                                 p.SetValue(model, Convert.ToInt32(lineArray[i]), null); 44                             } 45                             else if (p.PropertyType == typeof(string)) 46                             { 47                                 p.SetValue(model, lineArray[i], null); 48                             } 49                         } 50  51                         dataList.Add(model); 52                     } 53                 } 54             } 55         } 56  57         /// <summary> 58         /// 新增一个缓存 59         /// </summary> 60         /// <param name="t"></param> 61         public static void Add(T t) 62         { 63             lock (dataList) 64             { 65                 dataList.Add(t); 66  67                 WriteFile(); 68             } 69         } 70  71         /// <summary> 72         /// 读取缓存集合 73         /// </summary> 74         /// <returns></returns> 75         public static List<T> GetAll() 76         { 77             lock (dataList) 78             { 79                 return dataList; 80             } 81         } 82  83         /// <summary> 84         /// 写入缓存文件(全量) 85         /// </summary> 86         private static void WriteFile() 87         { 88             StringBuilder content = new StringBuilder(); 89             foreach (var item in dataList) 90             { 91                 List<string> list = new List<string>(); 92                 var ps = typeof(T).GetProperties(); 93                 foreach (var p in ps) 94                 { 95                     object p_object = p.GetValue(item, null); 96                     string value = p_object.ToString(); 97                     list.Add(value); 98                 } 99 100                 content.AppendLine(string.Join(SEP_STR, list.ToArray()));101             }102 103             File.WriteAllText(cachePath, content.ToString(), Encoding.UTF8);104         }105     }
版本2,通用文件缓存(适合一般场景)

  虽然,第二个版本出来了,但是大多数时候,我们创建缓存都是在已有的类上面进行操作,不然每次创建缓存可能就需要一个CacheModel这样一个对象了,

这样还有,并不是所有的字段我们都是需要进入缓存文件,这样的情况该如何操作呢,于是我们再次优化了一下代码,出现了目前来说的第三个版本了。

第三个版本


  这里,就会新增几个类了,为了解决第二个版本不能解决的问题,当然具体使用还是要看业务场景,因为,更通用就代表更依赖配置了。(代码类)

  这里需要几个基本类,用来保存临时管理的。

 

 1     /// <summary> 2     /// 特性:指定属性的排序和是否出现在缓存中使用 3     /// </summary> 4     public class CacheOrderAttribute : Attribute 5     { 6         public int Index { get; set; } 7     } 8  9     /// <summary>10     /// 对字符串分割的结果的值进行排序11     /// </summary>12     public class CacheIndexInfo13     {14         public int Index { get; set; }15 16         public string Value { get; set; }17     }18 19     /// <summary>20     /// 对字段的属性进行排序21     /// </summary>22     public class PropertyIndexInfo23     {24         public int Index { get; set; }25 26         public PropertyInfo PropertyInfo { get; set; }27     }
特性和通用缓存用到的类

  有了特性,我们就能对单个类的属性进行特性筛查,排序,最终得到我们需要的和不需要的,最开始改好了,楼主测试了一下,速度上还可以,但是数据了一多,

这种每次全部写入文件的方式就low了,于是改成了Append的方式,大大提升了速度。同时添加了一个类,对具体分割的值进行调整的。代码如下:

  1 /// <summary>  2     /// 文件缓存共有类  3     /// </summary>  4     /// <typeparam name="T">类</typeparam>  5     public class File_Common_Cache<T> where T : new()  6     {  7         /// <summary>  8         /// 缓存分隔符  9         /// </summary> 10         private static string SEP_STR = "---"; 11  12         /// <summary> 13         /// 缓存临时对象集合 14         /// </summary> 15         private static List<T> dataList = new List<T>(); 16  17         /// <summary> 18         /// 缓存文本路径 19         /// </summary> 20         private static string cachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "cache", typeof(T).Name.ToString() + ".txt"); 21  22         static File_Common_Cache() 23         { 24             string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "cache"); 25             if (!Directory.Exists(dir)) 26             { 27                 Directory.CreateDirectory(dir); 28             } 29  30             if (File.Exists(cachePath)) 31             { 32                 Type t = typeof(T); 33                 string[] lines = File.ReadAllLines(cachePath, Encoding.UTF8); 34                 foreach (var line in lines) 35                 { 36                     string[] lineArray = line.Split(new string[] { SEP_STR }, StringSplitOptions.None); 37                     if (line.Contains(SEP_STR)) 38                     { 39                         List<PropertyIndexInfo> list = new List<PropertyIndexInfo>(); 40                         T model = new T(); 41                         PropertyInfo[] ps = t.GetProperties(); 42                         foreach (var p in ps) 43                         { 44                             var ads = p.GetCustomAttributesData(); 45                             if (ads.Count > 0) 46                             { 47                                 int index = Convert.ToInt32(ads[0].NamedArguments[0].TypedValue.Value); 48                                 list.Add(new PropertyIndexInfo() { Index = index, PropertyInfo = p }); 49                             } 50                         } 51  52                         list = list.OrderBy(p => p.Index).ToList(); 53                         for (int i = 0; i < list.Count; i++) 54                         { 55                             var pt = list[i].PropertyInfo.PropertyType; 56                             if (pt == typeof(int)) 57                             { 58                                 list[i].PropertyInfo.SetValue(model, Convert.ToInt32(lineArray[i]), null); 59                             } 60                             else if (pt == typeof(string)) 61                             { 62                                 list[i].PropertyInfo.SetValue(model, lineArray[i], null); 63                             } 64                             else if (pt == typeof(DateTime)) 65                             { 66                                 list[i].PropertyInfo.SetValue(model, Convert.ToDateTime(lineArray[i]), null); 67                             } 68                             else 69                             { 70                                 try 71                                 { 72                                     list[i].PropertyInfo.SetValue(model, (object)lineArray[i], null); 73                                 } 74                                 catch 75                                 { 76                                     throw new Exception("不支持属性类型(仅支持,int,string,DateTime,object)"); 77                                 } 78                             } 79                         } 80  81                         dataList.Add(model); 82                     } 83                 } 84             } 85         } 86  87         /// <summary> 88         /// 初始化配置(修改默认分割和保存文件使用) 89         /// </summary> 90         /// <param name="sep_str">分隔符</param> 91         /// <param name="fileName">缓存文件名</param> 92         public static void InitSet(string sep_str, string fileName) 93         { 94             SEP_STR = sep_str; 95             cachePath = fileName; 96         } 97  98         /// <summary> 99         /// 新增一个缓存100         /// </summary>101         /// <param name="t"></param>102         public static void Add(T t)103         {104             lock (dataList)105             {106                 dataList.Add(t);107 108                 AppendFile(t);109             }110         }111 112         /// <summary>113         /// 移除一个缓存114         /// </summary>115         /// <param name="t"></param>116         public static void Remove(T t)117         {118 119         }120 121         /// <summary>122         /// 读取缓存集合123         /// </summary>124         /// <returns></returns>125         public static List<T> GetAll()126         {127             lock (dataList)128             {129                 return dataList;130             }131         }132 133         /// <summary>134         /// 写入缓存文件(全量)135         /// </summary>136         private static void WriteFile()137         {138             StringBuilder content = new StringBuilder();139             foreach (var item in dataList)140             {141                 List<CacheIndexInfo> list = new List<CacheIndexInfo>();142                 var ps = typeof(T).GetProperties();143                 foreach (var p in ps)144                 {145                     var ads = p.GetCustomAttributesData();146                     if (ads.Count > 0)147                     {148                         int index = Convert.ToInt32(ads[0].NamedArguments[0].TypedValue.Value);149                         object p_object = p.GetValue(item, null);150                         string value = string.Empty;151                         if (p.PropertyType == typeof(DateTime))152                         {153                             value = p_object == null ? DateTime.Parse("1900-1-1").ToString("yyyy-MM-dd HH:mm:ss") :154                                 Convert.ToDateTime(p_object).ToString("yyyy-MM-dd HH:mm:ss");155                         }156                         else157                         {158                             value = p_object == null ? "" : p_object.ToString();159                         }160 161                         list.Add(new CacheIndexInfo() { Index = index, Value = value });162                     }163                 }164 165                 list = list.OrderBy(a => a.Index).ToList();166                 content.AppendLine(string.Join(SEP_STR, (from f in list select f.Value).ToArray()));167             }168 169             File.WriteAllText(cachePath, content.ToString(), Encoding.UTF8);170         }171 172         /// <summary>173         /// 写入缓存文件(附加)174         /// </summary>175         /// <param name="t"></param>176         private static void AppendFile(T t)177         {178             StringBuilder content = new StringBuilder();179             List<CacheIndexInfo> list = new List<CacheIndexInfo>();180             var ps = typeof(T).GetProperties();181             foreach (var p in ps)182             {183                 var ads = p.GetCustomAttributesData();184                 if (ads.Count > 0)185                 {186                     int index = Convert.ToInt32(ads[0].NamedArguments[0].TypedValue.Value);187                     object p_object = p.GetValue(t, null);188                     string value = string.Empty;189                     if (p.PropertyType == typeof(DateTime))190                     {191                         value = p_object == null ? DateTime.Parse("1900-1-1").ToString("yyyy-MM-dd HH:mm:ss") :192                             Convert.ToDateTime(p_object).ToString("yyyy-MM-dd HH:mm:ss");193                     }194                     else195                     {196                         value = p_object == null ? "" : p_object.ToString();197                     }198 199                     list.Add(new CacheIndexInfo() { Index = index, Value = value });200                 }201             }202 203             list = list.OrderBy(a => a.Index).ToList();204             content.AppendLine(string.Join(SEP_STR, (from f in list select f.Value).ToArray()));205             File.AppendAllText(cachePath, content.ToString(), Encoding.UTF8);206         }207     }
终版(文件缓存类)

测试代码


 1 class Program 2     { 3         static void Main(string[] args) 4         { 5             TInfo info = new TInfo(); 6             info.Name = "test"; 7             info.Age = 10; 8             info.Test = "我是测试字符串"; 9             var list = File_Common_Cache<TInfo>.GetAll();10             DateTime startTime = DateTime.Now;11             for (int i = 0; i < 1000; i++)12             {13                 File_Common_Cache<TInfo>.Add(info);14             }15 16             TimeSpan span = DateTime.Now - startTime;17             Console.WriteLine(span.TotalMilliseconds);18             Console.ReadLine();19         }20     }21 22     public class TInfo23     {24         [CacheOrder(Index = 0)]25         public string Name { get; set; }26 27         [CacheOrder(Index = 2)]28         public int Age { get; set; }29 30         [CacheOrder(Index = 1)]31         public string Test { get; set; }32     }
测试代码

测试结果:1秒不到,还是可以。

总结


  没啥好总结的,但是不这样写,感觉不规范。写代码的过程中,总是会遇到,写着写着就变成体力活的代码,这个时候,我们就应该认识到问题了,把体力活改变一下,就不再是体力活。

让代码更简单,让生活个多彩。

  不足之处,望包含,拍砖,丢鸡蛋。

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台