寫在開頭數據庫
今天就放假了,照理說應該寫今年的總結了,可是回頭一看,好久沒有寫過技術類的文字了,仍是先不吐槽了。緩存
關於文件緩存ide
寫了不少的代碼,經常在寫EXE(定時任務)或者寫小站點(數據的使用和客戶端調用之間)都須要用到緩存,數據在內存和文本都保留一個總體。測試
固然也能夠寫到數據庫,不過我的以爲不方便查看和管理。(數據量不大)優化
第一個版本ui
通常來講,就是一個緩存類,而後存放緩存文件路徑,真實數據集合,讀寫集合,讀寫文件。spa
先提供一個公用類3d
1 public class TestInfo 2 { 3 public string Name { get; set; } 4 5 public int Age { get; set; } 6 7 public string Value { get; set; } 8 }
而後是第一個對文件讀寫操做的緩存了code
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 else 46 { 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 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 }
雖然,第二個版本出來了,可是大多數時候,咱們建立緩存都是在已有的類上面進行操做,否則每次建立緩存可能就須要一個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 CacheIndexInfo 13 { 14 public int Index { get; set; } 15 16 public string Value { get; set; } 17 } 18 19 /// <summary> 20 /// 對字段的屬性進行排序 21 /// </summary> 22 public class PropertyIndexInfo 23 { 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 else 157 { 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 else 195 { 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 TInfo 23 { 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秒不到,仍是能夠。
總結
沒啥好總結的,可是不這樣寫,感受不規範。寫代碼的過程當中,老是會遇到,寫着寫着就變成體力活的代碼,這個時候,咱們就應該認識到問題了,把體力活改變一下,就再也不是體力活。
讓代碼更簡單,讓生活個多彩。
不足之處,望包含,拍磚,丟雞蛋。