using MuchInfo.Chart.Data.EnumTypes; using MuchInfo.Chart.Data.Interfaces; using MuchInfo.Chart.Data.Models; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace MuchInfo.Chart.DataAccess { /// /// 文件JSON存储 /// public class FileDataAccess : IDataAccess { #region Methods #region Public Methods /// /// 获取数据 /// /// 商品代码 /// 周期类型 /// 起始时间 /// 结束时间 /// 记录条数 public IEnumerable GetDataPoints(string symbol, CycleType cycleType, DateTime startTime, DateTime endTime, int totalCount) { if (string.IsNullOrWhiteSpace(symbol)) return null; //周期为Nono,默认为Day var filePath = CombineFilePath(symbol, (cycleType == CycleType.None ? CycleType.Day : cycleType)); if (!File.Exists(filePath)) return null; return GetDataPoints(filePath, startTime, endTime, totalCount); } /// /// 获取数据 /// /// The file path. /// 起始时间 /// 结束时间 /// 记录条数 /// IEnumerable{IBarDataPoint}. private IEnumerable GetDataPoints(string filePath, DateTime startTime, DateTime endTime, int totalCount) { try { IList dataSoure; //获取数据 using (StreamReader file = File.OpenText(filePath)) { var serializer = new JsonSerializer(); try { dataSoure = (IList)serializer.Deserialize(file, typeof(IList)); } catch { return null; } } if (dataSoure == null || !dataSoure.Any()) return null; //记录条数小于零,默认取100条 //返回数据按日间顺排序 var count = totalCount <= 0 ? 100 : totalCount; if (startTime > endTime) { return dataSoure.Where(z => z.Date <= endTime) .OrderByDescending(z => z.Date) .Take(count).OrderBy(z => z.Date); } else { return dataSoure.Where(z => z.Date >= startTime && z.Date <= endTime) .OrderByDescending(z => z.Date) .Take(count).OrderBy(z => z.Date); } } catch (Exception ex) { throw ex; } } /// /// 保存数据 /// /// 商品代码 /// 周期类型 /// 保存的数据 /// public void SaveDataPoints(string symbol, CycleType cycleType, IList dataPoints) { if (string.IsNullOrWhiteSpace(symbol) || cycleType == CycleType.None || dataPoints == null) return; var filePath = CombineFilePath(symbol, cycleType); SaveDataPoints(filePath, dataPoints); } /// /// Saves the data points. /// /// The file path. /// The data points. private void SaveDataPoints(string filePath, IList dataPoints) { try { IList totalDataPoints; if (File.Exists(filePath)) { //获取源数据 IList source; try { using (StreamReader file = File.OpenText(filePath)) { var serializer = new JsonSerializer(); source = (IList)serializer.Deserialize(file, typeof(IList)); } } catch { //反序列化出错,删除源文件,重新写入目标数据 source = new List(); File.Delete(filePath); } //合并数据 totalDataPoints = CombineDataPoints(source == null ? null : source.ToList(), dataPoints).ToList(); } else { totalDataPoints = dataPoints; var fileInfo = new FileInfo(filePath); //创建目录 if (fileInfo.Directory != null && !Directory.Exists(fileInfo.Directory.FullName)) { Directory.CreateDirectory(fileInfo.Directory.FullName); } } //写JSON数据 using (var file = File.CreateText(filePath)) { var serializer = new JsonSerializer(); serializer.Serialize(file, totalDataPoints); } } catch (Exception ex) { throw ex; } } #endregion Public Methods #region Private Methods /// /// 合并数据 /// /// 源数据 /// 目标数据 private IEnumerable CombineDataPoints(IList source, IList destination) { if (source == null && destination == null) return new List(); if (source == null || !source.Any()) return destination; if (destination == null || !destination.Any()) return source; //找出源中存的数据 var interesct = destination.Intersect(source, new DataPointComparer()).ToList(); //找出源数据中不存在的数据 var except = destination.Except(source, new DataPointComparer()).ToList(); //从源中移除要更新的数据 //合并不存在的数据 //合并更新的数据 var result = source.Except(interesct, new DataPointComparer()) .Union(except) .Union(interesct); return result; } /// /// 生成数据文件路径 /// /// 商品代码 /// Type of the cycle. /// System.String. private string CombineFilePath(string symbol, CycleType cycleType) { return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data", symbol + "_" + cycleType.ToString() + ".txt"); } private string CombineFilePath(string symbol, TimeSpan timeSpan) { var timeSpanString = timeSpan.ToString().Replace(".", "_").Replace(":", "_"); return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data", symbol + "_" + timeSpanString + ".txt"); } /// /// 依据周期和记录条生成EndTime /// /// 时间 /// 周期 /// 记录条数 private DateTime CreateDateTime(DateTime time, CycleType type, int count) { switch (type) { case CycleType.Minute: return time.AddMinutes(count); case CycleType.Minute5: return time.AddMinutes(count * 5); case CycleType.Minute30: return time.AddMinutes(count * 30); case CycleType.Minute240: return time.AddMinutes(count * 240); case CycleType.Week: return time.AddDays(count * 7); case CycleType.Month: return time.AddMonths(count); case CycleType.Quarter: return time.AddMonths(count * 4); case CycleType.Year: return time.AddYears(count); default: return time.AddDays(count); } } #endregion Private Methods #endregion Methods public IEnumerable GetDataPoints(string symbol, TimeSpan timeSpan, DateTime startTime, DateTime endTime, int totalCount) { if (string.IsNullOrWhiteSpace(symbol)) return null; var filePath = CombineFilePath(symbol, timeSpan); if (!File.Exists(filePath)) return null; return GetDataPoints(filePath, startTime, endTime, totalCount); } /// /// 保存数据 /// /// 商品代码 /// The time span. /// 保存的数据 public void SaveDataPoints(string symbol, TimeSpan timeSpan, IList dataPoints) { if (string.IsNullOrWhiteSpace(symbol) || dataPoints == null) return; var filePath = CombineFilePath(symbol, timeSpan); SaveDataPoints(filePath, dataPoints); } } }