<< Click to Display Table of Contents >> Navigation: Проект > Элементы дерева объектов > Палитра ФБ > Служебные > Скрипт > Руководство и примеры > Работа с архивом данных > Генерация архива |
В целом генерация архива идентична записи данных, отличие лишь в том, что необходимо включить архивацию у переменной или выхода скрипта. Генерация архива средствами скрипта может потребоваться в различных ситуациях, но чаще всего это требуется если необходимо обрабатывать внешние архивные источники данных – файлы или базы данных. В качестве примера рассмотрим чтение архива из CSV файла.
Допустим у нас существует CSV файл, из которого нужно периодически (по сигналу) выполнять считывание данных с последующей записью в архив. CSV файл состоит из 6 столбцов – метки времени в формате Дата-Время, и 5 вещественных значений, поля разделены символом «точка с запятой».
Добавим скрипт, и добавим в него 2 входа – Считать и Имя файла, а также 5 выходов Параметр1 .. Параметр5.
Чтобы данные сохранялись нужно настроить архивацию у выходов. При этом для такого способа формирования архива лучше использовать периодическую архивацию с шагом в 00:00:00 – при таком способе будут записываться все значения, которые будут поступать из кода, а при остановке MasterSCADA не будет формироваться значение с признаком Норма-Останов. Включим данный способ архивации у каждого выходов Параметр1 - Параметр5.
Приступим к написанию кода. Для чтения файла мы будем использовать класс 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 = Считать;
}
}
Запустим режим исполнения и выполним считывание файла, указав его расположение на диске - данные считаются и запишутся на выходы.
Обратите внимание, что архив генерируется с признаком качества «Норма» (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.
Пример доработанного скрипта, а также файл для считывания доступен по ссылке.