Работа с внешними системами контроля и управления доступом (СКУД) — частая задача для программиста 1С. Обычно такие системы выгружают данные в текстовые файлы (*.txt), которые содержат информацию о дате, времени, типе события и идентификаторе сотрудника. В этой статье мы подробно разберем, как автоматизировать чтение таких файлов, правильно распарсить строки и избежать типичных ошибок при работе с файловой системой.
Для начала проанализируем структуру типичного лога СКУД. В нашем примере каждая запись находится на новой строке. Для последовательного чтения файла в 1С используется объект ЧтениеТекста. Этот метод является наиболее производительным для работы с большими объемами текстовых данных.
Рассмотрим базовый алгоритм чтения строк файла:
ПутьКФайлу = "C:\Logs\skud_export.txt";
Файл = Новый ЧтениеТекста(ПутьКФайлу, КодировкаТекста.ANSI);
ТекСтрока = Файл.ПрочитатьСтроку();
Пока ТекСтрока <> Неопределено Цикл
// Здесь будет выполняться парсинг строки
ОбработатьСтрокуЛога(ТекСтрока);
ТекСтрока = Файл.ПрочитатьСтроку();
КонецЦикла;
Файл.Закрыть();
Важно помнить, что если в файле используются специфические символы (например, кириллица), необходимо правильно указывать кодировку (обычно КодировкаТекста.ANSI или КодировкаТекста.UTF8).
Одной из главных задач является получение табельного номера сотрудника. В логах СКУД он часто располагается в конце строки и имеет фиксированную длину (например, 10 знаков с ведущими нулями). Рассмотрим несколько способов решения этой задачи.
Способ 1: Использование функции Прав()
Если мы точно знаем, что табельный номер всегда находится в конце и имеет фиксированную длину (10 символов), мы можем использовать простейшую функцию:
ТабНомер = Прав(СокрЛП(ТекСтрока), 10);
Способ 2: Поиск по разделителю с конца строки
Если длина табельного номера может варьироваться, но он всегда отделен пробелом, проанализируем ситуацию и применим поиск последнего пробела. Это более надежный метод, так как он не зависит от длины строки или количества нулей:
// Очищаем строку от лишних пробелов по краям
ЧистаяСтрока = СокрЛП(ТекСтрока);
// Находим позицию последнего пробела
ПозицияПробела = СтрНайти(ЧистаяСтрока, " ", НаправлениеПоиска.СКонца);
// Извлекаем все, что идет после этого пробела
ТабНомер = Сред(ЧистаяСтрока, ПозицияПробела + 1);
Выясним причину, по которой простая логика "первая запись — вход, последняя — выход" может давать сбои. Сотрудники могут выходить в течение дня (на обед или по делам), и в логах зафиксируется множество событий. Кроме того, возможны ошибки оборудования или ситуации, когда сотрудник зашел в один день, а вышел в другой.
Проанализируем пример строки: ...Этаж:Выход 0 10 Pertov A. 0000000024. В самой строке уже содержится маркер направления — "Вход" или "Выход". Вместо того чтобы вычислять статус по времени, гораздо надежнее искать эти ключевые слова в тексте:
Если СтрНайти(ТекСтрока, "Выход") > 0 Тогда
ТипСобытия = Перечисления.ТипыСобытийСКУД.Выход;
ИначеЕсли СтрНайти(ТекСтрока, "Вход") > 0 Тогда
ТипСобытия = Перечисления.ТипыСобытийСКУД.Вход;
КонецЕсли;
Важный нюанс: Обратите внимание на различие между событиями "Доступ предоставлен" и "Проход". Первое означает только факт прикладывания карты, а второе — физический поворот турникета. Для учета рабочего времени рекомендуется использовать именно события "Проход".
Разберем ситуацию, когда при попытке пометить файл как "прочитанный" (например, записав в него спецсимвол), 1С выдает ошибку совместного доступа. Это происходит потому, что объект ЧтениеТекста удерживает файл открытым.
Чтобы избежать этой ошибки, придерживайтесь следующих правил:
Файл.Закрыть() перед тем, как открывать этот же файл для записи или перемещения.Рассмотрим правильный алгоритм обработки файла по шагам:
// 1. Читаем данные и сохраняем в массив или таблицу значений
ДанныеЛога = Новый ТаблицаЗначений;
// ... (код чтения файла) ...
Файл.Закрыть(); // Обязательно освобождаем файл!
// 2. Обрабатываем данные в 1С (записываем в регистры)
ЗаписатьСобытияВБазу(ДанныеЛога);
// 3. Перемещаем файл в папку архива, чтобы не прочитать его повторно
ИмяФайла = "skud_" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd_HHmmss") + ".txt";
ПереместитьФайл(ПутьКФайлу, "C:\Logs\Archive\" + ИмяФайла);
Для того чтобы система работала автономно, рекомендуется настроить регламентное задание. Оно будет по расписанию проверять наличие файлов в определенной папке, считывать их и переносить в архив. Это избавит пользователей от необходимости ручного запуска обработки.
Также стоит рассмотреть возможность прямого подключения к базе данных СКУД через Внешние источники данных (если СКУД использует SQL или Access). Это позволит получать данные в реальном времени без промежуточных текстовых файлов, что значительно повысит надежность системы.