При организации обмена между 1С 7.7 и сторонним программным обеспечением часто возникает типовая задача: 1С формирует текстовый файл с заданием, внешняя программа его обрабатывает и записывает результат в файл-ответ, после чего 1С должна немедленно прочитать эти данные и продолжить выполнение алгоритма.
Использование фиксированной паузы (например, в 15 секунд) неудобно: если сторонний софт отработает за 1 секунду, пользователь будет вынужден ждать оставшиеся 14 секунд. Рассмотрим, как организовать процесс ожидания файла грамотно и без лишней потери времени.
Самый простой вариант без использования сторонних библиотек — регулярная проверка наличия файла через короткий интервал времени. В платформе 1С 7.7 для этого применяется процедура ОбработкаОжидания.
Разберем по шагам реализацию этого подхода:
ОбработкаОжидания("ПроверитьФайлОтвета", 1);.ПроверитьФайлОтвета проверяем наличие файла.ОбработкаОжидания("ПроверитьФайлОтвета", 0); и считываем данные.Посмотрим на пример реализации кода процедуры:
Процедура ПроверитьФайлОтвета()
ИмяФайла = КаталогОбмена + "response.txt";
Если ФС.СуществуетФайл(ИмяФайла) = 1 Тогда
// Отключаем таймер ожидания
ОбработкаОжидания("ПроверитьФайлОтвета", 0);
// Обрабатываем полученный ответ
ПрочитатьИОбработатьОтвет(ИмяФайла);
КонецЕсли;
КонецПроцедуры
Важное ограничение 1С 7.7: штатная ОбработкаОжидания останавливает свое выполнение, если у пользователя открыто модальное окно (например, предупреждение или диалог) или активировано меню программы.
Чтобы избежать постоянного опроса диска в цикле и получать уведомление мгновенно при появлении файла, разберем вариант с использованием внешних компонент (например, vk_ChangeNotification или возможностей FormEx).
Данные компоненты отслеживают изменения в файловой системе Windows (используя системный механизм FileSystemWatcher) и при появлении нужного файла генерируют в 1С внешнее событие.
Схема работы при таком подходе выглядит следующим образом:
ОбработкаВнешнегоСобытия(Источник, Событие, Данные) (аналогично работе со сканером штрихкодов).Проанализируем пример обработки внешнего события:
Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)
Если (Источник = "FileWatcher") И (Событие = "FileCreated") Тогда
Если Данные = "response.txt" Тогда
ОбработатьФайлОтвета(КаталогОбмена + Данные);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Если стороннее приложение является консольной утилитой или исполняемым файлом .exe, выставляемым из командной строки, от таймеров можно отказаться полностью. Выясним, как выполнить запуск программы синхронно с флагом ожидания завершения.
Для этого в 1С используется объект WScript.Shell и его метод Run со значением параметра WaitOnReturn = True:
WshShell = СоздатьОбъект("WScript.Shell");
// Запуск программы с ожиданием завершения (третий параметр = 1)
КодВозврата = WshShell.Run("C:\App\processor.exe -input task.txt", 1, 1);
ИмяФайлаОтвета = КаталогОбмена + "response.txt";
Если ФС.СуществуетФайл(ИмяФайлаОтвета) = 1 Тогда
ПрочитатьИОбработатьОтвет(ИмяФайлаОтвета);
КонецЕсли;
При реализации любого из способов важно предусмотреть технические нюансы работы с файловой системой, чтобы избежать ошибок считывания:
1. Чтение неполного или заблокированного файла
Сторонняя программа может сначала создать файл на диске, а затем продолжать запись данных в него течение нескольких секунд. Если 1С попытается прочитать файл в момент создания, произойдет ошибка доступа либо считывание пустого файла.
Для решения этой проблемы рекомендуется использовать файлы-флаги (сигнальные файлы):
response.txt и закрывает его.response.ready.response.ready, читает response.txt и затем удаляет оба файла.Если изменить логику сторонней программы нельзя, используйте обработку ошибки с помощью конструкции Попытка ... Исключение для проверки блокировки файла перед чтением:
Если ФС.СуществуетФайл(ИмяФайла) = 1 Тогда
Попытка
// Пробуем переименовать файл сам в себя для проверки блокировки сторонним процессом
ФС.ПереименоватьФайл(ИмяФайла, ИмяФайла);
// Если переименование прошло успешно - файл не заблокирован
ПрочитатьИОбработатьОтвет(ИмяФайла);
ФС.УдалитьФайл(ИмяФайла);
Исключение
// Файл еще дописывается внешней программой, ждем следующей итерации
КонецПопытки;
КонецЕсли;