/// <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> protected byte[] CreateEventBuffer(EventTableLight.Event ev) { byte[] evBuf = new byte[EventDataSize]; Array.Copy(BitConverter.GetBytes(Arithmetic.EncodeDateTime(ev.DateTime)), 0, evBuf, 0, 8); evBuf[8] = (byte)(ev.ObjNum % 256); evBuf[9] = (byte)(ev.ObjNum / 256); evBuf[10] = (byte)(ev.KPNum % 256); evBuf[11] = (byte)(ev.KPNum / 256); evBuf[12] = (byte)(ev.ParamID % 256); evBuf[13] = (byte)(ev.ParamID / 256); evBuf[14] = (byte)(ev.CnlNum % 256); evBuf[15] = (byte)(ev.CnlNum / 256); Array.Copy(BitConverter.GetBytes(ev.OldCnlVal), 0, evBuf, 16, 8); evBuf[24] = (byte)ev.OldCnlStat; Array.Copy(BitConverter.GetBytes(ev.NewCnlVal), 0, evBuf, 25, 8); evBuf[33] = (byte)ev.NewCnlStat; evBuf[34] = ev.Checked ? (byte)1 : (byte)0; evBuf[35] = (byte)(ev.UserID % 256); evBuf[36] = (byte)(ev.UserID / 256); string descr = ev.Descr ?? ""; if (descr.Length > MaxDescrLen) { descr = descr.Substring(0, MaxDescrLen); } evBuf[37] = (byte)descr.Length; Array.Copy(Encoding.Default.GetBytes(descr), 0, evBuf, 38, descr.Length); string data = ev.Data ?? ""; if (data.Length > MaxDataLen) { data = data.Substring(0, MaxDataLen); } evBuf[138] = (byte)data.Length; Array.Copy(Encoding.Default.GetBytes(data), 0, evBuf, 139, data.Length); return(evBuf); }
/// <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> /// Записать таблицу dataTable в файл или поток /// </summary> public void Update(DataTable dataTable) { if (dataTable == null) { throw new ArgumentNullException("dataTable"); } Stream stream = null; BinaryWriter writer = null; try { stream = ioStream == null ? new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite) : ioStream; writer = new BinaryWriter(stream, Encoding.Default); // запись заголовка byte fieldCnt = dataTable.Columns.Count > byte.MaxValue ? byte.MaxValue : (byte)dataTable.Columns.Count; writer.Write(fieldCnt); writer.Write((ushort)0); // резерв if (fieldCnt > 0) { // формирование и запись определений полей FieldDef[] fieldDefs = new FieldDef[fieldCnt]; int recSize = 2; // размер строки в файле byte[] fieldDefBuf = new byte[FieldDefSize]; fieldDefBuf[FieldDefSize - 1] = fieldDefBuf[FieldDefSize - 2] = 0; // резерв for (int i = 0; i < fieldCnt; i++) { FieldDef fieldDef = new FieldDef(); DataColumn col = dataTable.Columns[i]; Type type = col.DataType; if (type == typeof(int)) { fieldDef.DataType = DataTypes.Integer; fieldDef.DataSize = sizeof(int); fieldDef.MaxStrLen = 0; } else if (type == typeof(double)) { fieldDef.DataType = DataTypes.Double; fieldDef.DataSize = sizeof(double); fieldDef.MaxStrLen = 0; } else if (type == typeof(bool)) { fieldDef.DataType = DataTypes.Boolean; fieldDef.DataSize = 1; fieldDef.MaxStrLen = 0; } else if (type == typeof(DateTime)) { fieldDef.DataType = DataTypes.DateTime; fieldDef.DataSize = sizeof(double); fieldDef.MaxStrLen = 0; } else // String { fieldDef.DataType = DataTypes.String; int maxLen = Math.Min(col.MaxLength, MaxStringLen); fieldDef.DataSize = 2 /*запись длины*/ + Encoding.UTF8.GetMaxByteCount(maxLen); fieldDef.MaxStrLen = maxLen; } fieldDef.Name = col.ColumnName; fieldDef.AllowNull = col.AllowDBNull; recSize += fieldDef.DataSize; if (fieldDef.AllowNull) { recSize++; } fieldDefs[i] = fieldDef; fieldDefBuf[0] = (byte)fieldDef.DataType; Array.Copy(BitConverter.GetBytes((ushort)fieldDef.DataSize), 0, fieldDefBuf, 1, 2); Array.Copy(BitConverter.GetBytes((ushort)fieldDef.MaxStrLen), 0, fieldDefBuf, 3, 2); fieldDefBuf[5] = fieldDef.AllowNull ? (byte)1 : (byte)0; ConvertStr(fieldDef.Name, MaxFieldNameLen, MaxFieldNameDataSize, fieldDefBuf, 6, Encoding.ASCII); writer.Write(fieldDefBuf); } // запись строк byte[] rowBuf = new byte[recSize]; rowBuf[0] = rowBuf[1] = 0; // резерв foreach (DataRowView rowView in dataTable.DefaultView) { DataRow row = rowView.Row; int bufInd = 2; foreach (FieldDef fieldDef in fieldDefs) { int colInd = dataTable.Columns.IndexOf(fieldDef.Name); object val = colInd >= 0 ? row[colInd] : null; bool isNull = val == null || val == DBNull.Value; if (fieldDef.AllowNull) { rowBuf[bufInd++] = isNull ? (byte)1 : (byte)0; } switch (fieldDef.DataType) { case DataTypes.Integer: int intVal = isNull ? 0 : (int)val; Array.Copy(BitConverter.GetBytes(intVal), 0, rowBuf, bufInd, fieldDef.DataSize); break; case DataTypes.Double: double dblVal = isNull ? 0.0 : (double)val; Array.Copy(BitConverter.GetBytes(dblVal), 0, rowBuf, bufInd, fieldDef.DataSize); break; case DataTypes.Boolean: rowBuf[bufInd] = (byte)(isNull ? 0 : (bool)val ? 1 : 0); break; case DataTypes.DateTime: double dtVal = isNull ? 0.0 : Arithmetic.EncodeDateTime((DateTime)val); Array.Copy(BitConverter.GetBytes(dtVal), 0, rowBuf, bufInd, fieldDef.DataSize); break; default: string strVal = isNull ? "" : val.ToString(); ConvertStr(strVal, fieldDef.MaxStrLen, fieldDef.DataSize, rowBuf, bufInd, Encoding.UTF8); break; } bufInd += fieldDef.DataSize; } writer.Write(rowBuf); } } } 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; EventTableLight eventTableLight = null; DataTable dataTable = null; try { if (dest is EventTableLight) { eventTableLight = dest as EventTableLight; } else if (dest is DataTable) { dataTable = dest as DataTable; } else { throw new ScadaException("Destination object is invalid."); } // определение даты событий в таблице DateTime date = Arithmetic.ExtractDate(tableName); // подготовка объекта для хранения данных if (eventTableLight != null) { eventTableLight.Clear(); eventTableLight.TableName = tableName; } else // dataTable != null { // формирование структуры таблицы dataTable.BeginLoadData(); dataTable.DefaultView.Sort = ""; if (dataTable.Columns.Count == 0) { dataTable.Columns.Add("Number", typeof(int)); dataTable.Columns.Add("DateTime", typeof(DateTime)).DefaultValue = date; dataTable.Columns.Add("ObjNum", typeof(int)).DefaultValue = 0; dataTable.Columns.Add("KPNum", typeof(int)).DefaultValue = 0; dataTable.Columns.Add("ParamID", typeof(int)).DefaultValue = 0; dataTable.Columns.Add("CnlNum", typeof(int)).DefaultValue = 0; dataTable.Columns.Add("OldCnlVal", typeof(double)).DefaultValue = 0.0; dataTable.Columns.Add("OldCnlStat", typeof(int)).DefaultValue = 0; dataTable.Columns.Add("NewCnlVal", typeof(double)).DefaultValue = 0.0; dataTable.Columns.Add("NewCnlStat", typeof(int)).DefaultValue = 0; dataTable.Columns.Add("Checked", typeof(bool)).DefaultValue = false; dataTable.Columns.Add("UserID", typeof(int)).DefaultValue = 0; dataTable.Columns.Add("Descr", typeof(string)); dataTable.Columns.Add("Data", typeof(string)); dataTable.DefaultView.AllowNew = false; dataTable.DefaultView.AllowEdit = false; dataTable.DefaultView.AllowDelete = false; } else { DataColumn colDateTime = dataTable.Columns["DateTime"]; if (colDateTime != null) { colDateTime.DefaultValue = date; } dataTable.Rows.Clear(); } } // заполнение таблицы из файла stream = ioStream == null ? new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) : ioStream; reader = new BinaryReader(stream); Byte[] eventBuf = new byte[EventDataSize]; // буфер данных события int evNum = 1; // порядковый номер события while (stream.Position < stream.Length) { int readSize = reader.Read(eventBuf, 0, EventDataSize); if (readSize == EventDataSize) { // создание события на основе считанных данных EventTableLight.Event ev = new EventTableLight.Event(); ev.Number = evNum; evNum++; double time = BitConverter.ToDouble(eventBuf, 0); int hour, min, sec; Arithmetic.DecodeTime(time, out hour, out min, out sec); ev.DateTime = new DateTime(date.Year, date.Month, date.Day, hour, min, sec); ev.ObjNum = BitConverter.ToUInt16(eventBuf, 8); ev.KPNum = BitConverter.ToUInt16(eventBuf, 10); ev.ParamID = BitConverter.ToUInt16(eventBuf, 12); ev.CnlNum = BitConverter.ToUInt16(eventBuf, 14); ev.OldCnlVal = BitConverter.ToDouble(eventBuf, 16); ev.OldCnlStat = eventBuf[24]; ev.NewCnlVal = BitConverter.ToDouble(eventBuf, 25); ev.NewCnlStat = eventBuf[33]; ev.Checked = eventBuf[34] > 0; ev.UserID = BitConverter.ToUInt16(eventBuf, 35); ev.Descr = BytesToStr(eventBuf, 37); ev.Data = BytesToStr(eventBuf, 138); // создание строки заполняемой таблицы if (eventTableLight != null) { eventTableLight.AllEvents.Add(ev); // быстрее, чем eventTableLight.AddEvent(ev) } else // dataTable != null { DataRow row = dataTable.NewRow(); row["Number"] = ev.Number; row["DateTime"] = ev.DateTime; row["ObjNum"] = ev.ObjNum; row["KPNum"] = ev.KPNum; row["ParamID"] = ev.ParamID; row["CnlNum"] = ev.CnlNum; row["OldCnlVal"] = ev.OldCnlVal; row["OldCnlStat"] = ev.OldCnlStat; row["NewCnlVal"] = ev.NewCnlVal; row["NewCnlStat"] = ev.NewCnlStat; row["Checked"] = ev.Checked; row["UserID"] = ev.UserID; row["Descr"] = ev.Descr; row["Data"] = ev.Data; dataTable.Rows.Add(row); } } } } catch (EndOfStreamException) { // нормальная ситуация окончания файла } catch { fillTime = DateTime.MinValue; throw; } finally { if (fileMode) { if (reader != null) { reader.Close(); } if (stream != null) { stream.Close(); } } if (eventTableLight != null) { eventTableLight.LastFillTime = fillTime; } else if (dataTable != null) { dataTable.EndLoadData(); dataTable.AcceptChanges(); dataTable.DefaultView.Sort = "Number"; } } }