Генерация архива

<< Click to Display Table of Contents >>

Navigation:  Проект > Элементы дерева объектов > Палитра ФБ > Служебные > Скрипт > Руководство и примеры > Работа с архивом данных >

Генерация архива

В целом генерация архива идентична записи данных, отличие лишь в том, что необходимо включить архивацию у переменной или выхода скрипта. Генерация архива средствами скрипта может потребоваться в различных ситуациях, но чаще всего это требуется если необходимо обрабатывать внешние архивные источники данных – файлы или базы данных. В качестве примера рассмотрим чтение архива из CSV файла.

Допустим у нас существует CSV файл, из которого нужно периодически (по сигналу) выполнять считывание данных с последующей записью в архив. CSV файл состоит из 6 столбцов – метки времени в формате Дата-Время, и 5 вещественных значений, поля разделены символом «точка с запятой».

sluzhebnie_skript_rukovodstvo_i_primery_generaciya_arhiva

Добавим скрипт, и добавим в него 2 входа – Считать и Имя файла, а также 5 выходов Параметр1 .. Параметр5.

sluzhebnie_skript_rukovodstvo_i_primery_generaciya_arhiva1

Чтобы данные сохранялись нужно настроить архивацию у выходов. При этом для такого способа формирования архива лучше использовать периодическую архивацию с шагом в 00:00:00 – при таком способе будут записываться все значения, которые будут поступать из кода, а при остановке MasterSCADA не будет формироваться значение с признаком Норма-Останов. Включим данный способ архивации у каждого выходов Параметр1 - Параметр5.

sluzhebnie_skript_rukovodstvo_i_primery_generaciya_arhiva2

Приступим к написанию кода. Для чтения файла мы будем использовать класс StreamReader – данный класс позволяет считывать символы из потока байтов в заданной кодировки. Для того чтобы данный класс был доступен в коде нужно в секции using объявить класс:

using System.IO;

Объявим переменную M, в которую будем сохранять значение входа Считать - для выполнения кода по переднему фронту на входе. Также перед тем как выполнять код нужно убедится, что задан путь файла. Для этого проверим его на значение Null, а также убедимся, что имя не пустое – для этого нужно сравнить ее со свойством string.Empty или просто с пустой строкой - "".

public override void Execute()
{
 if (Считать == true && M == false && Файл != string.Empty && Файл != null)
 {
 }
 M = Считать;
}

 

Для того чтобы открыть файл на чтение, создадим класс StreamReader. Данный класс имеет несколько конструкторов, мы вызовем конструктор с одним параметром – именем файла. Описание данного конструктора можно прочитать здесь:

https://msdn.microsoft.com/ru-ru/library/f2ke0fzy(v=vs.110).aspx

Поскольку у нас файл содержит только цифры и несколько символов, такого вызова будет достаточно. Однако если читать файл, содержащий символы (особенно кириллические), то следует вызывать метод с тремя аргументами – именем, кодировкой и флагом обнаружения порядка байта:

https://msdn.microsoft.com/ru-ru/library/ms143457(v=vs.110).aspx

Класс StreamReader мы также вызовем через оператор using, чтобы обеспечить очистку ресурсов при выходе из данного кода (закрытие файла, и закрытие всех указателей).

using (var file = new StreamReader(Файл))
{
}

Переменная file для обращения к файлу готова, теперь нам нужно поочередно считывать строки, и разбирать строку на элементы - метку времени и значения, а после записать на выход.

Для считывания строки используется метод ReadLine, который возвращает считанную строку.

var line=file.ReadLine();//считывание строк из файла

Чтобы считать все строки мы будем использовать цикл while – данный цикл выполняется пока условие равно true. Условием выхода из цикла в данном случае будет окончание файла – в этом случае переменная line будет равна null.

var line = file.ReadLine();//считывание строк из файла
while (line != null)
{
    //здесь мы обработаем строку
    line = file.ReadLine();
}

Теперь нужно обработать строку line – разбить ее на составляющие. Каждая строка у нас представляет собой метку времени и 5 значений, разделенных символом «точка с запятой». Для разбора строки на составляющие нужно использовать метод строки Split. Данный метод разбирает строку на составляющие разделенные заданным символом. В качестве результата метод возвращает массив строк.

String[] substrings = line.Split(';'); //разбор строки на составляющие

Массив у нас содержит 6 строк. Нулевой элемент массива – метка времени, но она все еще представлена в виде строки. Для перевода ее во время у класса DateTime есть метод Parse – данный метод преобразует строку в эквивалентное ему значение времени.

var Time = DateTime.Parse(substrings[0]);

Получить значение числа можно аналогичным образом - вызвав этот же метод но уже у класса Double.

При обработке времени, необходимо иметь ввиду, что при записи в архив MasterSCADA время должно быть в формате UTC (по Гринвичу). Если в вашем файле метки времени представлены в локальном времени, то необходимо сделать преобразование в формату UTC. Для этого есть специальный метод - ToUniversalTime. Например:

Time = Time.ToUniversalTime();

Теперь зная как получить значения и время, можно записать их на выход скрипта. На прошлом уроке мы использовали для этого такой метод:

var item1=(ITreePinHlp)HostFB.TreeItemHlp.ParentObject.GetChild("Команда 1");
item1.GetRTPin().SetValue(new PinValue(1));

Если архив генерируется для внешней переменной скрипта, то можно применить этот же метод. Единственное отличие, нужно PinValue сформировать со значением и меткой времени:

new PinValue(Value,Time)

Но если нам нужно записать значение на выход скрипта, то можно воспользоваться методом SetValue:

SetValue("Выход", new PinValue(Value,Time));

Имена выходов у нас имеют имена Параметр1..Параметр5. Можно сделать 5 строк вызывающих метод SetValue, либо произвести запись в цикле. Остановимся на втором варианте – реализуем его с помощью цикла for.

for (int i = 1; i <= 5; i++)
{
    SetValue("Параметр" + i.ToString(), new PinValue(Double.Parse(substrings[i]), Time));
}

В итоге наш код будет иметь следующий вид:

public partial class ФБ : ScriptBase
{
    bool? M = false;
    public override void Execute()
    {
        if (Считать == true && M == false && Файл != string.Empty && Файл != null)
        {
            using (var file = new StreamReader(Файл))
            {
                var line = file.ReadLine();
                while (line != null)
                {
                    String[] substrings = line.Split(';'); //разбор строки на составляющие             
                    var Time = DateTime.Parse(substrings[0]);
                    for (int i = 1; i <= 5; i++)
                    {
                        SetValue("Параметр" + i.ToString(), new PinValue(Double.Parse(substrings[i]), Time));
                    }
                    line = file.ReadLine();//считывание строк из файла
                }
            }
        }
        M = Считать;
    }
}

 

Запустим режим исполнения и выполним считывание файла, указав его расположение на диске - данные считаются и запишутся на выходы.

sluzhebnie_skript_rukovodstvo_i_primery_generaciya_arhiva3

Обратите внимание, что архив генерируется с признаком качества «Норма» (192 – Good). Если необходимо генерировать архив с различными метками времени, то нужно сначала сформировать нужный вам признак качества. Для этого предназначен класс:

MasterSCADA.Hlp.Pins.PinQuality

Данный класс также имеет перегруженный конструктор, в один из которых можно передать значение признака качества. Например, инициализация класса с признаком качества Good (Норма):

var qual= new MasterSCADA.Hlp.Pins.PinQuality(192);

После этого можно вызвать другой конструктор класса PinValue содержащий признак качества

var qual= new MasterSCADA.Hlp.Pins.PinQuality(192);
SetValue("Параметр"+i.ToString(), new PinValue(Double.Parse(substrings[i]),qual,Time));

Также стоит дополнить наш скрипт защитой исполнения кода от ошибок, которые могут возникнуть при обработке файла или его отсутствии. Для этого также применяется оператор try-catch.

Пример доработанного скрипта, а также файл для считывания доступен по ссылке.