/// <summary> /// Converts the specified snapshot table to CSV. /// </summary> public void ConvertToCsv(SrezTable srezTable) { if (srezTable == null) { throw new ArgumentNullException("srezTable"); } Stream stream = GetStream(); StreamWriter writer = null; try { int srezCnt = srezTable.SrezList.Count; if (srezCnt > 0) { // output the channels present in the last snapshot int[] cnlNums = srezTable.SrezList.Values[srezCnt - 1].CnlNums; // prepare a writer writer = new StreamWriter(stream); // output the table header writer.Write("[DateTime]"); foreach (int cnlNum in cnlNums) { writer.Write(";[" + cnlNum + "]"); } writer.WriteLine(); // output the data foreach (SrezTableLight.Srez srez in srezTable.SrezList.Values) { writer.Write(srez.DateTime.ToString(Localization.Culture)); foreach (int cnlNum in cnlNums) { writer.Write(";"); SrezTableLight.CnlData cnlData = srez.GetCnlData(cnlNum); if (cnlData.Stat > 0) { writer.Write(cnlData.Val.ToString(Localization.Culture)); } } writer.WriteLine(); } } } finally { if (fileMode) { writer?.Dispose(); stream?.Dispose(); } } }
/// <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 ScadaException("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 = 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 ScadaException("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; ScadaUtils.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> 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(ScadaUtils.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> /// Write changes to the slicing table to a file or stream. /// </summary> public void Update(SrezTable srezTable) { if (srezTable == null) { throw new ArgumentNullException(nameof(srezTable)); } Stream stream = null; BinaryWriter writer = null; try { stream = ioStream ?? new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite); writer = new BinaryWriter(stream); // record modified slices foreach (var srez in srezTable.ModifiedSrezList) { stream.Seek(srez.Position + 8, SeekOrigin.Begin); writer.Write(GetCnlDataBuf(srez.CnlData)); } // setting the recording position of the added slices to the stream, // restore slice table if necessary var 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) { var buf = new byte[offset - stream.Position]; stream.Write(buf, 0, buf.Length); } else { stream.Seek(offset, SeekOrigin.Begin); } } // record added slices var prevSrezDescr = lastSrez?.SrezDescr; foreach (var srez in srezTable.AddedSrezList) { // recording cutoff channel numbers writer.Write(srez.SrezDescr.Equals(prevSrezDescr) ? EmptyCnlNumsBuf : GetSrezDescrBuf(srez.SrezDescr)); prevSrezDescr = srez.SrezDescr; // slice data entry srez.Position = stream.Position; writer.Write(ScadaUtils.EncodeDateTime(srez.DateTime)); writer.Write(GetCnlDataBuf(srez.CnlData)); lastSrez = srez; } // confirmation of successful saving of changes srezTable.AcceptChanges(); srezTable.LastStoredSrez = lastSrez; } finally { if (fileMode) { writer?.Close(); stream?.Close(); } } }