Exemple #1
0
        /// <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();
                    }
                }
            }
        }
Exemple #2
0
        /// <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);
        }
Exemple #3
0
        /// <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();
                    }
                }
            }
        }
Exemple #4
0
        /// <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();
                }
            }
        }
Exemple #5
0
        /// <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();
                    }
                }
            }
        }
Exemple #6
0
        /// <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";
                }
            }
        }