Как скопировать файл с FTP на локальный компьютер в 1С без блокировки интерфейса?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с внешними ресурсами, такими как FTP-серверы, разработчики часто сталкиваются с проблемой: метод КопироватьФайл() или его аналоги «замораживают» клиентское приложение до завершения процесса загрузки. Если файл весит несколько сотен мегабайт, пользователь видит неактивное окно программы, что создает впечатление зависания системы. В этой статье мы подробно разберем, как реализовать загрузку файлов на сторону клиента, сохранив отзывчивость интерфейса и обеспечив визуализацию прогресса.

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

Решение 1. Использование асинхронных методов платформы (8.3.18+)

Начиная с версии платформы 8.3.18, фирма «1С» внедрила механизм асинхронности на основе обещаний (Promises) и ключевого слова Ждать (Await). Это наиболее современный и правильный способ решения проблемы блокировки потока интерфейса.

Рассмотрим применение метода КопироватьФайлАсинх(). В отличие от старых методов с использованием ОписаниеОповещения, данный подход позволяет писать код в линейном стиле, при этом выполнение кода в основном потоке будет приостановлено без блокировки отрисовки окон.

Разберем пример реализации:


&НаКлиенте
Асинх Процедура СкачатьФайлАсинхронно(ИмяФайлаИсточника, ИмяФайлаПриемника)
    
    Попытка
        // Интерфейс не блокируется, пользователь может двигать окно
        Ждать КопироватьФайлАсинх(ИмяФайлаИсточника, ИмяФайлаПриемника);
        ПоказатьОповещениеПользователя("Загрузка завершена", , ИмяФайлаПриемника);
    Исключение
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка при копировании: " + КраткоеОписаниеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;
    
КонецПроцедуры

Главное преимущество этого метода — простота. Однако у него есть существенный минус: стандартный метод КопироватьФайлАсинх() не предоставляет встроенного события для отображения прогресса в процентах (0–100%).

Решение 2. Работа через объект FTPСоединение и асинхронные вызовы

Для более тонкой настройки работы с протоколом FTP рекомендуется использовать специализированный объект FTPСоединение. У него также существуют асинхронные аналоги методов получения файлов. Проанализируем, как это работает через НачатьПолучение().

Посмотрим на пример кода, который инициирует загрузку в неблокирующем режиме:


&НаКлиенте
Процедура НачатьЗагрузкуСFTP()
    
    ПараметрыСоединения = Новый FTPСоединение("ftp.example.com", 21, "Логин", "Пароль");
    Оповещение = Новый ОписаниеОповещения("ЗагрузкаЗавершена", ЭтотОбъект);
    
    // Метод не ждет окончания, а сразу возвращает управление интерфейсу
    ПараметрыСоединения.НачатьПолучение(Оповещение, "remote_file.zip", "C:\LocalFiles\file.zip");
    
    Состояние("Файл загружается в фоновом режиме...");
    
КонецПроцедуры

&НаКлиенте
Процедура ЗагрузкаЗавершена(Результат, ДополнительныеПараметры) Экспорт
    ТекстСообщения = "Файл успешно получен!";
    ПоказатьОповещениеПользователя(ТекстСообщения);
КонецПроцедуры

Хотя этот метод лучше справляется с отзывчивостью, вопрос индикации прогресса остается открытым. Чтобы решить его внутри 1С, нам придется прибегнуть к хитростям.

Решение 3. Отображение прогресса через обработчик ожидания

Если нам критически важно показывать пользователю, сколько мегабайт уже скачано, мы можем использовать комбинацию асинхронной загрузки и периодической проверки размера локального файла. Выясним алгоритм действий:

  1. Перед началом загрузки получаем размер файла на сервере методом FTPСоединение.Размер().
  2. Запускаем асинхронное получение файла.
  3. Подключаем обработчик ожидания (например, раз в 1 секунду).
  4. В обработчике проверяем текущий размер создаваемого локального файла через Файл.Размер().
  5. Вычисляем процент выполнения и обновляем Индикатор на форме.

Проанализируем пример кода для обновления прогресс-бара:


&НаКлиенте
Перем РазмерФайлаНаСервере;

&НаКлиенте
Процедура ОбновитьИндикаторЗагрузки()
    ЛокальныйФайл = Новый Файл("C:\LocalFiles\file.zip");
    Если ЛокальныйФайл.Существует() Тогда
        ТекущийРазмер = ЛокальныйФайл.Размер();
        Процент = (ТекущийРазмер / РазмерФайлаНаСервере) * 100;
        ЭтаФорма.ИндикаторЗагрузки = Процент;
    КонецЕсли;
КонецПроцедуры

Решение 4. Использование внешних утилит (cURL / PowerShell)

Для очень больших файлов и обеспечения максимальной стабильности интерфейса эффективно использовать внешние системные инструменты. Современные ОС Windows (10 и 11) уже включают в себя мощную консольную утилиту curl.

Преимущество этого метода заключается в том, что загрузка происходит в полностью независимом процессе. Мы можем запустить его скрыто, и 1С вообще не будет тратить ресурсы на обработку потока байтов.

Разберем пример вызова через ЗапуститьПриложение():


&НаКлиенте
Процедура СкачатьЧерезCurl()
    Команда = "curl -u user:password ftp://example.com/file.zip -o C:\temp\file.zip";
    
    // Запускаем процесс, не дожидаясь завершения (ДождатьсяЗавершения = Ложь)
    ЗапуститьПриложение(Команда, , Ложь);
    
    // Можно периодически проверять наличие файла или использовать лог-файл curl
КонецПроцедуры

Если нужно показать окно консоли с нативным прогрессом curl, установите параметр СпособОтображенияОкна в значение Максимизированное или Нормальное.

Решение 5. Побайтовое чтение через COM-объекты (WinHTTP)

Для реализации «честного» индикатора внутри 1С без внешних окон можно воспользоваться объектами Windows WinHttp.WinHttpRequest.5.1 и ADODB.Stream. Этот метод позволяет читать данные порциями в цикле.

Посмотрим на логику процесса:

  1. Создаем HTTP-запрос к FTP (если сервер поддерживает HTTP-доступ) или используем специализированные COM-библиотеки.
  2. В цикле считываем порцию данных (например, 64 КБ).
  3. Записываем порцию в поток ADODB.Stream.
  4. Вызываем ОбработкаПрерыванияПользователя(), чтобы 1С могла перерисовать интерфейс на каждой итерации.
  5. Обновляем прогресс на форме.

Важный момент: использование COM-объектов ограничивает кроссплатформенность (не будет работать на Linux-клиентах), но для Windows-инфраструктуры это дает самый полный контроль над процессом.

Резюме и рекомендации

Выбор метода зависит от версии вашей платформы и требований к интерфейсу:

Помните, что при работе с FTP на стороне клиента необходимо убедиться, что у пользователя есть права на запись в целевой каталог и настройки брандмауэра позволяют устанавливать исходящие соединения по соответствующим портам.

← На главную