/// <summary> /// Добавить копию среза в таблицу /// </summary> /// <remarks>Если в таблице уже существует срез с заданной меткой времени, /// то в него копируются данные из исходного среза</remarks> public Srez AddSrezCopy(Srez srcSrez, DateTime srezDT) { if (srcSrez == null) { throw new ArgumentNullException("srcSrez"); } Srez srez; SrezTableLight.Srez lightSrez; if (SrezList.TryGetValue(srezDT, out lightSrez)) { // изменение существующего в таблице среза srez = (Srez)lightSrez; // возможно исключение InvalidCastException srez.CopyDataFrom(srcSrez); if (srez.State == DataRowState.Unchanged) { srez.State = DataRowState.Modified; ModifiedSrezList.Add(srez); } } else { // создание и добавление нового среза в таблицу srez = new SrezTable.Srez(srezDT, srcSrez); srez.State = DataRowState.Added; AddedSrezList.Add(srez); SrezList.Add(srezDT, srez); } return(srez); }
private bool editMode; // режим редактирования /// <summary> /// Конструктор /// </summary> private FrmSrezTableEdit() { InitializeComponent(); errLog = null; srezAdapter = null; srezTable = null; dataTable1 = null; dataTable2 = null; selSrez = null; editMode = false; }
/// <summary> /// Создать таблицу, состоящую из одного среза, в файле или потоке /// </summary> /// <remarks>Для записи таблицы текущего среза</remarks> public void Create(SrezTable.Srez srez, DateTime srezDT) { if (srez == null) { throw new ArgumentNullException("srez"); } Stream stream = null; BinaryWriter writer = null; try { stream = ioStream == null ? new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite) : ioStream; writer = new BinaryWriter(stream); writer.Write(GetSrezDescrBuf(srez.SrezDescr)); writer.Write(Arithmetic.EncodeDateTime(srezDT)); writer.Write(GetCnlDataBuf(srez.CnlData)); stream.SetLength(stream.Position); } finally { if (fileMode) { if (writer != null) { writer.Close(); } if (stream != null) { stream.Close(); } } } }
/// <summary> /// Записать изменения таблицы срезов в файл или поток /// </summary> public void Update(SrezTable srezTable) { if (srezTable == null) { throw new ArgumentNullException("srezTable"); } Stream stream = null; BinaryWriter writer = null; try { stream = ioStream == null ? new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite) : ioStream; writer = new BinaryWriter(stream); // запись изменённых срезов foreach (SrezTable.Srez srez in srezTable.ModifiedSrezList) { stream.Seek(srez.Position + 8, SeekOrigin.Begin); writer.Write(GetCnlDataBuf(srez.CnlData)); } // установка позиции записи добавленных срезов в поток, // восстановление таблицы срезов в случае необходимости SrezTable.Srez lastSrez = srezTable.LastStoredSrez; if (lastSrez == null) { stream.Seek(0, SeekOrigin.Begin); } else { stream.Seek(0, SeekOrigin.End); long offset = lastSrez.Position + lastSrez.CnlNums.Length * 9 + 8; if (stream.Position < offset) { byte[] buf = new byte[offset - stream.Position]; stream.Write(buf, 0, buf.Length); } else { stream.Seek(offset, SeekOrigin.Begin); } } // запись добавленных срезов SrezTable.SrezDescr prevSrezDescr = lastSrez == null ? null : lastSrez.SrezDescr; foreach (SrezTable.Srez srez in srezTable.AddedSrezList) { // запись номеров каналов среза if (srez.SrezDescr.Equals(prevSrezDescr)) { writer.Write(EmptyCnlNumsBuf); } else { writer.Write(GetSrezDescrBuf(srez.SrezDescr)); } prevSrezDescr = srez.SrezDescr; // запись данных среза srez.Position = stream.Position; writer.Write(Arithmetic.EncodeDateTime(srez.DateTime)); writer.Write(GetCnlDataBuf(srez.CnlData)); lastSrez = srez; } // подтверждение успешного сохранения изменений srezTable.AcceptChanges(); srezTable.LastStoredSrez = lastSrez; } finally { if (fileMode) { if (writer != null) { writer.Close(); } if (stream != null) { stream.Close(); } } } }
/// <summary> /// Заполнить объект dest из файла срезов FileName /// </summary> protected void FillObj(object dest) { Stream stream = null; BinaryReader reader = null; DateTime fillTime = DateTime.Now; SrezTableLight srezTableLight = dest as SrezTableLight; DataTable dataTable = dest as DataTable; Trend trend = dest as Trend; SrezTable srezTable = srezTableLight as SrezTable; SrezTableLight.Srez lastStoredSrez = null; try { if (srezTableLight == null && dataTable == null && trend == null) { throw new Exception("Destination object is invalid."); } // подготовка объекта для хранения данных if (srezTableLight != null) { srezTableLight.Clear(); srezTableLight.TableName = tableName; if (srezTable != null) { srezTable.BeginLoadData(); } } else if (dataTable != null) { // формирование структуры таблицы dataTable.BeginLoadData(); dataTable.DefaultView.Sort = ""; if (dataTable.Columns.Count == 0) { dataTable.Columns.Add("DateTime", typeof(DateTime)); dataTable.Columns.Add("CnlNum", typeof(int)); dataTable.Columns.Add("Val", typeof(double)); dataTable.Columns.Add("Stat", typeof(int)); dataTable.DefaultView.AllowNew = false; dataTable.DefaultView.AllowEdit = false; dataTable.DefaultView.AllowDelete = false; } else { dataTable.Rows.Clear(); } } else // trend != null { trend.Clear(); trend.TableName = tableName; } // заполнение объекта данными stream = ioStream == null ? new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) : ioStream; reader = new BinaryReader(stream); DateTime date = Arithmetic.ExtractDate(tableName); // определение даты срезов SrezTable.SrezDescr srezDescr = null; // описание среза int[] cnlNums = null; // ссылка на номера входных каналов из описания среза while (stream.Position < stream.Length) { // считывание списка номеров каналов и КС int cnlNumCnt = reader.ReadUInt16(); if (cnlNumCnt > 0) { // загрузка номеров каналов в буфер для увеличения скорости работы int cnlNumSize = cnlNumCnt * 2; byte[] buf = new byte[cnlNumSize]; int readSize = reader.Read(buf, 0, cnlNumSize); // создание описания среза и заполнение номеров каналов из буфера // с проверкой их уникальности и упорядоченности if (readSize == cnlNumSize) { int prevCnlNum = -1; srezDescr = new SrezTable.SrezDescr(cnlNumCnt); cnlNums = srezDescr.CnlNums; for (int i = 0; i < cnlNumCnt; i++) { int cnlNum = BitConverter.ToUInt16(buf, i * 2); if (prevCnlNum >= cnlNum) { throw new Exception("Table is incorrect."); } cnlNums[i] = prevCnlNum = cnlNum; } srezDescr.CalcCS(); } } else if (srezDescr == null) { throw new Exception("Table is incorrect."); } // считывание и проверка КС ushort cs = reader.ReadUInt16(); bool csOk = cnlNumCnt > 0 ? srezDescr.CS == cs : cs == 1; // считывание данных среза int cnlCnt = cnlNums.Length; // количество каналов в срезе int srezDataSize = cnlCnt * 9; // размер данных среза if (csOk) { long srezPos = stream.Position; double time = reader.ReadDouble(); int hour, min, sec; Arithmetic.DecodeTime(time, out hour, out min, out sec); DateTime srezDT = new DateTime(date.Year, date.Month, date.Day, hour, min, sec); // инициализация нового среза SrezTableLight.Srez srez; if (srezTable != null) { srez = new SrezTable.Srez(srezDT, srezDescr) { State = DataRowState.Unchanged, Position = srezPos }; } else if (srezTableLight != null) { srez = new SrezTableLight.Srez(srezDT, cnlCnt); cnlNums.CopyTo(srez.CnlNums, 0); } else // srezTableLight == null { srez = null; } // считывание данных входных каналов int bufInd = 0; double val; byte stat; if (trend != null) { // выбор данных требуемого канала для тренда int index = Array.BinarySearch <int>(cnlNums, trend.CnlNum); if (index >= 0) { stream.Seek(index * 9, SeekOrigin.Current); byte[] buf = new byte[9]; int readSize = reader.Read(buf, 0, 9); if (readSize == 9) { ExtractCnlData(buf, ref bufInd, out val, out stat); Trend.Point point = new Trend.Point(srezDT, val, stat); trend.Points.Add(point); stream.Seek(srezDataSize - (index + 1) * 9, SeekOrigin.Current); } } else { stream.Seek(srezDataSize, SeekOrigin.Current); } } else { // загрузка данных среза в буфер для увеличения скорости работы byte[] buf = new byte[srezDataSize]; int readSize = reader.Read(buf, 0, srezDataSize); // заполение таблицы срезов из буфера if (srezTableLight != null) { for (int i = 0; i < cnlCnt; i++) { ExtractCnlData(buf, ref bufInd, out val, out stat); srez.CnlNums[i] = cnlNums[i]; srez.CnlData[i].Val = val; srez.CnlData[i].Stat = stat; if (bufInd >= readSize) { break; } } srezTableLight.AddSrez(srez); lastStoredSrez = srez; } else // dataTable != null { for (int i = 0; i < cnlCnt; i++) { ExtractCnlData(buf, ref bufInd, out val, out stat); DataRow row = dataTable.NewRow(); row["DateTime"] = srezDT; row["CnlNum"] = cnlNums[i]; row["Val"] = val; row["Stat"] = stat; dataTable.Rows.Add(row); if (bufInd >= readSize) { break; } } } } } else { // пропустить срез, считая его размер так, как при повторяющемся списке номеров каналов stream.Seek(srezDataSize + 8, SeekOrigin.Current); } } } catch (EndOfStreamException) { // нормальная ситуация окончания файла } catch { fillTime = DateTime.MinValue; throw; } finally { if (fileMode) { if (reader != null) { reader.Close(); } if (stream != null) { stream.Close(); } } if (srezTableLight != null) { srezTableLight.LastFillTime = fillTime; if (srezTable != null) { srezTable.LastStoredSrez = (SrezTable.Srez)lastStoredSrez; srezTable.EndLoadData(); } } else if (dataTable != null) { dataTable.EndLoadData(); dataTable.AcceptChanges(); dataTable.DefaultView.Sort = "DateTime, CnlNum"; } else if (trend != null) { trend.LastFillTime = fillTime; trend.Sort(); } } }
/// <summary> /// Записать принятый срез в таблицу архивных срезов /// </summary> private bool WriteReceivedSrez(SrezTable srezTable, SrezAdapter srezAdapter, SrezTableLight.Srez receivedSrez, DateTime srezDT, ref SrezTableLight.Srez arcSrez) { string fileName = ""; try { // получение существующего или создание нового архивного среза fileName = srezAdapter.FileName; SrezTableCache.FillSrezTable(srezTable, srezAdapter); SrezTable.Srez srez = srezTable.GetSrez(srezDT); bool addSrez; if (srez == null) { srez = new SrezTable.Srez(srezDT, srezDescr, receivedSrez); addSrez = true; } else { addSrez = false; } if (arcSrez == null) arcSrez = srez; // изменение архивного среза lock (calculator) { try { procSrez = srez; int cntCnt = receivedSrez.CnlNums.Length; for (int i = 0; i < cntCnt; i++) { int cnlNum = receivedSrez.CnlNums[i]; int cnlInd = srez.GetCnlIndex(cnlNum); InCnl inCnl; if (inCnls.TryGetValue(cnlNum, out inCnl) && cnlInd >= 0 && (inCnl.CnlTypeID == BaseValues.CnlTypes.TS || inCnl.CnlTypeID == BaseValues.CnlTypes.TI)) { // вычисление новых данных входного канала SrezTableLight.CnlData oldCnlData = srez.CnlData[cnlInd]; SrezTableLight.CnlData newCnlData = receivedSrez.CnlData[i]; if (newCnlData.Stat == BaseValues.CnlStatuses.Defined) newCnlData.Stat = BaseValues.CnlStatuses.Archival; CalcCnlData(inCnl, oldCnlData, ref newCnlData); // запись новых данных в архивный срез srez.CnlData[cnlInd] = newCnlData; } } } finally { procSrez = null; } } // вычисление дорасчётных каналов CalcDRCnls(drCnls, srez, false); if (addSrez) srezTable.AddSrez(srez); else srezTable.MarkSrezAsModified(srez); // запись изменений таблицы срезов srezAdapter.Update(srezTable); srezTable.FileModTime = File.GetLastWriteTime(fileName); return true; } catch (Exception ex) { string fileNameStr = string.IsNullOrEmpty(fileName) ? "" : Environment.NewLine + (Localization.UseRussian ? "Имя файла: " : "Filename: ") + fileName; AppLog.WriteAction(string.Format(Localization.UseRussian ? "Ошибка при записи принятого среза в таблицу архивных срезов: {0}{1}" : "Error writing received snapshot in the archive data table: {0}{1}", ex.Message, fileNameStr), Log.ActTypes.Exception); return false; } }
private string workState; // состояние работы #endregion Fields #region Constructors /// <summary> /// Конструктор /// </summary> public MainLogic() { AppDirs = new AppDirs(); AppLog = new Log(Log.Formats.Full); AppLog.Encoding = Encoding.UTF8; Settings = new Settings(); infoFileName = ""; thread = null; terminated = false; serverIsReady = false; startDT = DateTime.MinValue; workState = ""; comm = new Comm(this); calculator = new Calculator(this); inCnls = new SortedList<int, InCnl>(); drCnls = null; drmCnls = null; drhCnls = null; drCnlNums = null; drmCnlNums = null; drhCnlNums = null; avgCnlInds = null; ctrlCnls = new SortedList<int, CtrlCnl>(); users = new SortedList<string, User>(); formulas = new List<string>(); curSrez = null; curSrezMod = false; srezDescr = null; minAvgData = null; hrAvgData = null; activeDTs = null; curSrezAdapter = null; curSrezCopyAdapter = null; eventAdapter = null; eventCopyAdapter = null; minSrezTableCache = null; hrSrezTableCache = null; modules = new List<ModLogic>(); }
/// <summary> /// Цикл работы сервера (метод вызывается в отдельном потоке) /// </summary> private void Execute() { try { // запись информации о работе приложения workState = WorkStateNames.Normal; WriteInfo(); // выполнение действий модулей RaiseOnServerStart(); // инициализация адаптеров таблиц текущего среза и событий curSrezAdapter = new SrezAdapter(); curSrezCopyAdapter = new SrezAdapter(); eventAdapter = new EventAdapter(); eventCopyAdapter = new EventAdapter(); curSrezAdapter.FileName = ServerUtils.BuildCurFileName(Settings.ArcDir); curSrezCopyAdapter.FileName = ServerUtils.BuildCurFileName(Settings.ArcCopyDir); eventAdapter.Directory = Settings.ArcDir + "Events" + Path.DirectorySeparatorChar; eventCopyAdapter.Directory = Settings.ArcCopyDir + "Events" + Path.DirectorySeparatorChar; // инициализация кэша таблиц минутных и часовых срезов minSrezTableCache = new SortedList<DateTime, SrezTableCache>(); hrSrezTableCache = new SortedList<DateTime, SrezTableCache>(); // инициализация описания создаваемых срезов int cnlCnt = inCnls.Count; srezDescr = new SrezTable.SrezDescr(cnlCnt); for (int i = 0; i < cnlCnt; i++) srezDescr.CnlNums[i] = inCnls.Values[i].CnlNum; srezDescr.CalcCS(); // загрузка исходного текущего среза из файла SrezTableLight.Srez curSrezSrc = null; SrezTableLight tblCurSrezScr = new SrezTableLight(); try { if (File.Exists(curSrezAdapter.FileName)) { curSrezAdapter.Fill(tblCurSrezScr); if (tblCurSrezScr.SrezList.Count > 0) curSrezSrc = tblCurSrezScr.SrezList.Values[0]; } if (curSrezSrc == null) AppLog.WriteAction(Localization.UseRussian ? "Текущий срез не загружен" : "Current data are not loaded", Log.ActTypes.Action); else AppLog.WriteAction(Localization.UseRussian ? "Текущий срез загружен" : "Current data are loaded", Log.ActTypes.Action); } catch (Exception ex) { AppLog.WriteAction((Localization.UseRussian ? "Ошибка при загрузке текущего среза: " : "Error loading current data: ") + ex.Message, Log.ActTypes.Exception); } // инициализация текущего среза, предназначенного для формироваться данных сервера curSrez = new SrezTable.Srez(DateTime.MinValue, srezDescr, curSrezSrc); // инициализация данных для усреднения и времени активности каналов minAvgData = new AvgData[cnlCnt]; hrAvgData = new AvgData[cnlCnt]; activeDTs = new DateTime[cnlCnt]; DateTime nowDT = DateTime.Now; for (int i = 0; i < cnlCnt; i++) { minAvgData[i] = new AvgData() { Sum = 0.0, Cnt = 0 }; hrAvgData[i] = new AvgData() { Sum = 0.0, Cnt = 0 }; activeDTs[i] = nowDT; } // цикл работы сервера nowDT = DateTime.MaxValue; DateTime today = nowDT.Date; DateTime prevDT; DateTime writeCurSrezDT = DateTime.MinValue; DateTime writeMinSrezDT = DateTime.MinValue; DateTime writeHrSrezDT = DateTime.MinValue; DateTime calcMinDT = DateTime.MinValue; DateTime calcHrDT = DateTime.MinValue; DateTime clearCacheDT = nowDT; bool writeCur = Settings.WriteCur || Settings.WriteCurCopy; bool writeCurOnMod = Settings.WriteCurPer <= 0; bool writeMin = (Settings.WriteMin || Settings.WriteMinCopy) && Settings.WriteMinPer > 0; bool writeHr = (Settings.WriteHr || Settings.WriteHrCopy) && Settings.WriteHrPer > 0; curSrezMod = false; serverIsReady = true; while (!terminated) { prevDT = nowDT; nowDT = DateTime.Now; today = nowDT.Date; // расчёт времени записи срезов и вычисления значений дорасчётных каналов // при переводе времени назад или при первом проходе цикла if (prevDT > nowDT) { writeCurSrezDT = nowDT; writeMinSrezDT = CalcNextTime(nowDT, Settings.WriteMinPer); writeHrSrezDT = CalcNextTime(nowDT, Settings.WriteHrPer); calcMinDT = drmCnls.Count > 0 ? CalcNextTime(nowDT, 60) : DateTime.MaxValue; calcHrDT = drhCnls.Count > 0 ? CalcNextTime(nowDT, 3600) : DateTime.MaxValue; } // удаление устаревших файлов срезов и событий при изменении даты или при первом проходе цикла if (prevDT.Date != today) { ClearArchive(Settings.ArcDir + "Min", "m*.dat", today.AddDays(-Settings.StoreMinPer)); ClearArchive(Settings.ArcDir + "Hour", "h*.dat", today.AddDays(-Settings.StoreHrPer)); ClearArchive(Settings.ArcDir + "Events", "e*.dat", today.AddDays(-Settings.StoreEvPer)); ClearArchive(Settings.ArcCopyDir + "Min", "m*.dat", today.AddDays(-Settings.StoreMinPer)); ClearArchive(Settings.ArcCopyDir + "Hour", "h*.dat", today.AddDays(-Settings.StoreHrPer)); ClearArchive(Settings.ArcCopyDir + "Events", "e*.dat", today.AddDays(-Settings.StoreEvPer)); } lock (curSrez) { // установка недостоверности неактивных каналов SetUnreliable(); // вычисление дорасчётных каналов и выполнение действий модулей CalcDRCnls(drCnls, curSrez, true); RaiseOnCurDataCalculated(drCnlNums, curSrez); // вычисление минутных каналов и выполнение действий модулей if (calcMinDT <= nowDT) { CalcDRCnls(drmCnls, curSrez, true); RaiseOnCurDataCalculated(drmCnlNums, curSrez); calcMinDT = CalcNextTime(nowDT, 60); curSrezMod = true; } // вычисление часовых каналов и выполнение действий модулей if (calcHrDT <= nowDT) { CalcDRCnls(drhCnls, curSrez, true); RaiseOnCurDataCalculated(drhCnlNums, curSrez); calcHrDT = CalcNextTime(nowDT, 3600); curSrezMod = true; } // запись текущего среза if ((writeCurSrezDT <= nowDT || writeCurOnMod && curSrezMod) && writeCur) { if (writeCurOnMod) { WriteSrez(SrezTypes.Cur, nowDT); curSrezMod = false; writeCurSrezDT = DateTime.MaxValue; } else { WriteSrez(SrezTypes.Cur, writeCurSrezDT); writeCurSrezDT = CalcNextTime(nowDT, Settings.WriteCurPer); } } // запись минутного среза if (writeMinSrezDT <= nowDT && writeMin) { WriteSrez(SrezTypes.Min, writeMinSrezDT); writeMinSrezDT = CalcNextTime(nowDT, Settings.WriteMinPer); } // запись часового среза if (writeHrSrezDT <= nowDT && writeHr) { WriteSrez(SrezTypes.Hour, writeHrSrezDT); writeHrSrezDT = CalcNextTime(nowDT, Settings.WriteHrPer); } } // очистка устаревших данных кэша if (nowDT - clearCacheDT > CacheClearSpan || nowDT < clearCacheDT /*время переведено назад*/) { clearCacheDT = nowDT; ClearSrezTableCache(minSrezTableCache, MinCacheStorePer, MinCacheCapacity); ClearSrezTableCache(hrSrezTableCache, HourCacheStorePer, HourCacheCapacity); } // запись информации о работе приложения WriteInfo(); // задержка для экономиии ресурсов процессора Thread.Sleep(100); } } finally { // выполнение действий модулей RaiseOnServerStop(); // запись информации о работе приложения workState = WorkStateNames.Stopped; WriteInfo(); } }
/// <summary> /// Добавить копию среза в таблицу /// </summary> /// <remarks>Если в таблице уже существует срез с заданной меткой времени, /// то в него копируются данные из исходного среза</remarks> public Srez AddSrezCopy(Srez srcSrez, DateTime srezDT) { if (srcSrez == null) throw new ArgumentNullException("srcSrez"); Srez srez; SrezTableLight.Srez lightSrez; if (SrezList.TryGetValue(srezDT, out lightSrez)) { // изменение существующего в таблице среза srez = (Srez)lightSrez; // возможно исключение InvalidCastException srez.CopyDataFrom(srcSrez); if (srez.State == DataRowState.Unchanged) { srez.State = DataRowState.Modified; ModifiedSrezList.Add(srez); } } else { // создание и добавление нового среза в таблицу srez = new SrezTable.Srez(srezDT, srcSrez); srez.State = DataRowState.Added; AddedSrezList.Add(srez); SrezList.Add(srezDT, srez); } return srez; }
/// <summary> /// Заполнить объект dest из файла срезов FileName /// </summary> protected void FillObj(object dest) { Stream stream = null; BinaryReader reader = null; DateTime fillTime = DateTime.Now; SrezTableLight srezTableLight = dest as SrezTableLight; DataTable dataTable = dest as DataTable; Trend trend = dest as Trend; SrezTable srezTable = srezTableLight as SrezTable; SrezTableLight.Srez lastStoredSrez = null; try { if (srezTableLight == null && dataTable == null && trend == null) throw new Exception("Destination object is invalid."); // подготовка объекта для хранения данных if (srezTableLight != null) { srezTableLight.Clear(); srezTableLight.TableName = tableName; if (srezTable != null) srezTable.BeginLoadData(); } else if (dataTable != null) { // формирование структуры таблицы dataTable.BeginLoadData(); dataTable.DefaultView.Sort = ""; if (dataTable.Columns.Count == 0) { dataTable.Columns.Add("DateTime", typeof(DateTime)); dataTable.Columns.Add("CnlNum", typeof(int)); dataTable.Columns.Add("Val", typeof(double)); dataTable.Columns.Add("Stat", typeof(int)); dataTable.DefaultView.AllowNew = false; dataTable.DefaultView.AllowEdit = false; dataTable.DefaultView.AllowDelete = false; } else { dataTable.Rows.Clear(); } } else // trend != null { trend.Clear(); trend.TableName = tableName; } // заполнение объекта данными stream = ioStream == null ? new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) : ioStream; reader = new BinaryReader(stream); DateTime date = Arithmetic.ExtractDate(tableName); // определение даты срезов SrezTable.SrezDescr srezDescr = null; // описание среза int[] cnlNums = null; // ссылка на номера входных каналов из описания среза while (stream.Position < stream.Length) { // считывание списка номеров каналов и КС int cnlNumCnt = reader.ReadUInt16(); if (cnlNumCnt > 0) { // загрузка номеров каналов в буфер для увеличения скорости работы int cnlNumSize = cnlNumCnt * 2; byte[] buf = new byte[cnlNumSize]; int readSize = reader.Read(buf, 0, cnlNumSize); // создание описания среза и заполнение номеров каналов из буфера // с проверкой их уникальности и упорядоченности if (readSize == cnlNumSize) { int prevCnlNum = -1; srezDescr = new SrezTable.SrezDescr(cnlNumCnt); cnlNums = srezDescr.CnlNums; for (int i = 0; i < cnlNumCnt; i++) { int cnlNum = BitConverter.ToUInt16(buf, i * 2); if (prevCnlNum >= cnlNum) throw new Exception("Table is incorrect."); cnlNums[i] = prevCnlNum = cnlNum; } srezDescr.CalcCS(); } } else if (srezDescr == null) { throw new Exception("Table is incorrect."); } // считывание и проверка КС ushort cs = reader.ReadUInt16(); bool csOk = cnlNumCnt > 0 ? srezDescr.CS == cs : cs == 1; // считывание данных среза int cnlCnt = cnlNums.Length; // количество каналов в срезе int srezDataSize = cnlCnt * 9; // размер данных среза if (csOk) { long srezPos = stream.Position; double time = reader.ReadDouble(); int hour, min, sec; Arithmetic.DecodeTime(time, out hour, out min, out sec); DateTime srezDT = new DateTime(date.Year, date.Month, date.Day, hour, min, sec); // инициализация нового среза SrezTableLight.Srez srez; if (srezTable != null) { srez = new SrezTable.Srez(srezDT, srezDescr) { State = DataRowState.Unchanged, Position = srezPos }; } else if (srezTableLight != null) { srez = new SrezTableLight.Srez(srezDT, cnlCnt); cnlNums.CopyTo(srez.CnlNums, 0); } else // srezTableLight == null { srez = null; } // считывание данных входных каналов int bufInd = 0; double val; byte stat; if (trend != null) { // выбор данных требуемого канала для тренда int index = Array.BinarySearch<int>(cnlNums, trend.CnlNum); if (index >= 0) { stream.Seek(index * 9, SeekOrigin.Current); byte[] buf = new byte[9]; int readSize = reader.Read(buf, 0, 9); if (readSize == 9) { ExtractCnlData(buf, ref bufInd, out val, out stat); Trend.Point point = new Trend.Point(srezDT, val, stat); trend.Points.Add(point); stream.Seek(srezDataSize - (index + 1) * 9, SeekOrigin.Current); } } else { stream.Seek(srezDataSize, SeekOrigin.Current); } } else { // загрузка данных среза в буфер для увеличения скорости работы byte[] buf = new byte[srezDataSize]; int readSize = reader.Read(buf, 0, srezDataSize); // заполение таблицы срезов из буфера if (srezTableLight != null) { for (int i = 0; i < cnlCnt; i++) { ExtractCnlData(buf, ref bufInd, out val, out stat); srez.CnlNums[i] = cnlNums[i]; srez.CnlData[i].Val = val; srez.CnlData[i].Stat = stat; if (bufInd >= readSize) break; } srezTableLight.AddSrez(srez); lastStoredSrez = srez; } else // dataTable != null { for (int i = 0; i < cnlCnt; i++) { ExtractCnlData(buf, ref bufInd, out val, out stat); DataRow row = dataTable.NewRow(); row["DateTime"] = srezDT; row["CnlNum"] = cnlNums[i]; row["Val"] = val; row["Stat"] = stat; dataTable.Rows.Add(row); if (bufInd >= readSize) break; } } } } else { // пропустить срез, считая его размер так, как при повторяющемся списке номеров каналов stream.Seek(srezDataSize + 8, SeekOrigin.Current); } } } catch (EndOfStreamException) { // нормальная ситуация окончания файла } catch { fillTime = DateTime.MinValue; throw; } finally { if (fileMode) { if (reader != null) reader.Close(); if (stream != null) stream.Close(); } if (srezTableLight != null) { srezTableLight.LastFillTime = fillTime; if (srezTable != null) { srezTable.LastStoredSrez = (SrezTable.Srez)lastStoredSrez; srezTable.EndLoadData(); } } else if (dataTable != null) { dataTable.EndLoadData(); dataTable.AcceptChanges(); dataTable.DefaultView.Sort = "DateTime, CnlNum"; } else if (trend != null) { trend.LastFillTime = fillTime; trend.Sort(); } } }
/// <summary> /// Создать и заполнить dataTable2 данными из srezTable /// </summary> private void FillDataTable2(DateTime srezDT) { DataTable newDataTable2 = new DataTable(); newDataTable2.Columns.Add("CnlNum", typeof(int)); newDataTable2.Columns.Add("Val", typeof(double)); newDataTable2.Columns.Add("Stat", typeof(int)); newDataTable2.DefaultView.AllowNew = false; newDataTable2.DefaultView.AllowEdit = editMode; newDataTable2.DefaultView.AllowDelete = false; selSrez = srezDT > DateTime.MinValue ? srezTable.GetSrez(srezDT) : null; if (selSrez != null) { newDataTable2.BeginLoadData(); bindingSource2.DataSource = null; // для ускорения изменения данных в таблице int cnlCnt = selSrez.CnlNums.Length; for (int i = 0; i < cnlCnt; i++) { DataRow row = newDataTable2.NewRow(); row["CnlNum"] = selSrez.CnlNums[i]; SrezTable.CnlData cnlData = selSrez.CnlData[i]; row["Val"] = cnlData.Val; row["Stat"] = cnlData.Stat; newDataTable2.Rows.Add(row); } newDataTable2.EndLoadData(); dataTable2 = newDataTable2; dataTable2.RowChanged += dataTable2_RowChanged; bindingSource2.DataSource = dataTable2; } }