private bool editMode; // режим редактирования /// <summary> /// Конструктор /// </summary> private FrmSrezTableEdit() { InitializeComponent(); errLog = null; srezAdapter = null; srezTable = null; dataTable1 = null; dataTable2 = null; selSrez = null; editMode = false; }
/// <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; } }
/// <summary> /// Записать срез в таблицу архивных (минутных или часовых) срезов /// </summary> private void WriteArcSrez(SrezTable srezTable, SrezAdapter srezAdapter, DateTime srezDT, AvgData[] avgData) { string fileName = ""; try { // заполнение таблицы срезов, если файл изменился fileName = srezAdapter.FileName; SrezTableCache.FillSrezTable(srezTable, srezAdapter); // добавление копии среза в таблицу SrezTable.Srez newSrez = srezTable.AddSrezCopy(curSrez, srezDT); // запись усредняемых данных bool changed = false; foreach (int cnlInd in avgCnlInds) { AvgData ad = avgData[cnlInd]; if (ad.Cnt > 0) { newSrez.CnlData[cnlInd] = new SrezTableLight.CnlData(ad.Sum / ad.Cnt, BaseValues.CnlStatuses.Defined); avgData[cnlInd] = new AvgData() { Sum = 0.0, Cnt = 0 }; // сброс changed = true; } } // вычисление дорасчётных каналов, если добавленый срез изменился if (changed) CalcDRCnls(drCnls, newSrez, false); // запись изменений таблицы срезов srezAdapter.Update(srezTable); srezTable.FileModTime = File.GetLastWriteTime(fileName); if (Settings.DetailedLog) AppLog.WriteAction(string.Format(Localization.UseRussian ? "Запись среза в таблицу {0} завершена" : "Writing snapshot in the {0} table is completed", srezTable.Descr), Log.ActTypes.Action); } catch (Exception ex) { string fileNameStr = string.IsNullOrEmpty(fileName) ? "" : Environment.NewLine + (Localization.UseRussian ? "Имя файла: " : "Filename: ") + fileName; AppLog.WriteAction(string.Format(Localization.UseRussian ? "Ошибка при записи среза в таблицу архивных срезов: {0}{1}" : "Error writing snapshot in the archive data table: {0}{1}", ex.Message, fileNameStr), Log.ActTypes.Exception); } }
/// <summary> /// Заполнить таблицу срезов /// </summary> public static void FillSrezTable(SrezTable srezTable, SrezAdapter srezAdapter) { string fileName = srezAdapter.FileName; if (File.Exists(fileName)) { // определение времени последнего изменения файла таблицы срезов DateTime fileModTime = File.GetLastWriteTime(fileName); // загрузка данных, если файл был изменён if (srezTable.FileModTime != fileModTime) { srezAdapter.Fill(srezTable); srezTable.FileModTime = fileModTime; } } else { srezTable.Clear(); } }
/// <summary> /// Конструктор /// </summary> public SrezTableCache(DateTime date) { AccessDT = DateTime.Now; Date = date; SrezTable = new SrezTable(); SrezTableCopy = new SrezTable(); SrezAdapter = new SrezAdapter(); SrezCopyAdapter = new SrezAdapter(); }
/// <summary> /// Получить буфер описания структуры среза в формате сохранения /// </summary> protected byte[] GetSrezDescrBuf(SrezTable.SrezDescr srezDescr) { ushort cnlNumsLen = (ushort)srezDescr.CnlNums.Length; byte[] cnlNumsBuf = new byte[cnlNumsLen * 2 + 4]; cnlNumsBuf[0] = (byte)(cnlNumsLen % 256); cnlNumsBuf[1] = (byte)(cnlNumsLen / 256); int bufPos = 2; for (int i = 0; i < cnlNumsLen; i++) { ushort cnlNum = (ushort)srezDescr.CnlNums[i]; cnlNumsBuf[bufPos++] = (byte)(cnlNum % 256); cnlNumsBuf[bufPos++] = (byte)(cnlNum / 256); } cnlNumsBuf[bufPos++] = (byte)(srezDescr.CS % 256); cnlNumsBuf[bufPos++] = (byte)(srezDescr.CS / 256); return cnlNumsBuf; }
/// <summary> /// Получить буфер данных среза в формате сохранения /// </summary> protected byte[] GetCnlDataBuf(SrezTable.CnlData[] cnlData) { int cnlCnt = cnlData.Length; byte[] srezDataBuf = new byte[cnlCnt * 9]; for (int i = 0, k = 0; i < cnlCnt; i++) { SrezTable.CnlData data = cnlData[i]; BitConverter.GetBytes(data.Val).CopyTo(srezDataBuf, k); srezDataBuf[k + 8] = (byte)data.Stat; k += 9; } return srezDataBuf; }
/// <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> /// Создать таблицу, состоящую из одного среза, в файле или потоке /// </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(); } } }
private void btnRefresh_Click(object sender, EventArgs e) { // перезагрузка таблицы SrezTable newSrezTable = new SrezTable(); if (LoadSrezTable(srezAdapter, errLog, ref newSrezTable)) { srezTable = newSrezTable; FillDataTable1(); try { dataTable2.DefaultView.RowFilter = txtFilter.Text; } catch { txtFilter.Text = ""; } } }
/// <summary> /// Отобразить форму редактирования или просмотра таблицы срезов /// </summary> public static void Show(string directory, string tableName, bool editMode, Log errLog) { if (string.IsNullOrEmpty(directory)) throw new ArgumentException("directory"); if (string.IsNullOrEmpty(tableName)) throw new ArgumentException("tableName"); if (errLog == null) throw new ArgumentNullException("errLog"); SrezAdapter srezAdapter = new SrezAdapter(); srezAdapter.Directory = directory; srezAdapter.TableName = tableName; SrezTable srezTable = new SrezTable(); if (LoadSrezTable(srezAdapter, errLog, ref srezTable)) { FrmSrezTableEdit frmSrezTableEdit = new FrmSrezTableEdit(); frmSrezTableEdit.errLog = errLog; frmSrezTableEdit.srezAdapter = srezAdapter; frmSrezTableEdit.srezTable = srezTable; frmSrezTableEdit.editMode = editMode; frmSrezTableEdit.ShowDialog(); } }
/// <summary> /// Загрузить таблицу срезов /// </summary> private static bool LoadSrezTable(SrezAdapter srezAdapter, Log errLog, ref SrezTable srezTable) { try { srezAdapter.Fill(srezTable); return true; } catch (Exception ex) { string errMsg = AppPhrases.LoadSrezTableError + ":\r\n" + ex.Message; if (errLog != null) errLog.WriteAction(errMsg, Log.ActTypes.Exception); ScadaUtils.ShowError(errMsg); return false; } finally { Cursor.Current = Cursors.Default; } }