Почему файл не выгружается на FTP в 1С при успешном выполнении кода и как это исправить?

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

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

Анализ исходного кода и выявление критических ошибок

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


Процедура ОтправитьДокументXML(Документ)
    
    ИмяВременногоФайлаXML = ПолучитьСтрокуXML(Документ);
    
    Если ОтправлятьНаFTP Тогда
        Попытка    
            FTP = Новый FTPСоединение(АдресFTPСервера, ПортFTPСервера, ЛогинFTP, ПарольFTP, Неопределено, ПассивныйРежимFTPСервера, 0);
            Если ЗначениеЗаполнено(ДиректорияFTPСервера) Тогда
                FTP.УстановитьТекущийКаталог(ДиректорияFTPСервера);
            Иначе
                FTP.УстановитьТекущийКаталог("/");
            КонецЕсли;
            ИмяФайлаНаФТП = "";
            ИмяФайлаНаФТП = "Order_" + Документ.Номер + "_" + Формат(Документ.Дата, "ДФ=dd.MM.yy") + ".xml";
            FTP.Записать(ИмяВременногоФайлаXML, ИмяФайлаНаФТП);
        Исключение
        КонецПопытки;
    КонецЕсли;
    
КонецПроцедуры

На первый взгляд код выглядит стандартно и работоспособно, однако в нем скрыты две критические ошибки, которые в совокупности приводят к "молчаливому" сбою работы алгоритма.

Ошибка №1: Передача содержимого файла вместо пути к нему на диске.

Обратим внимание на строку ИмяВременногоФайлаXML = ПолучитьСтрокуXML(Документ);. Функция ПолучитьСтрокуXML возвращает текстовое представление XML-документа (то есть саму XML-структуру в виде длинной строки с тегами). Однако метод Записать объекта FTPСоединение ожидает первым параметром строку, которая содержит полный путь к локальному файлу на жестком диске компьютера (например, "C:\Temp\order.xml").

Когда платформа выполняет метод FTP.Записать(ИмяВременногоФайлаXML, ИмяФайлаНаФТП), она пытается интерпретировать XML-текст как путь к файлу. Естественно, операционная система сообщает, что файла с таким именем (состоящим из XML-разметки) не существует на диске, и генерирует исключение "Файл не найден".

Ошибка №2: Пустой блок обработки исключений.

Поскольку вызов метода Записать был обернут в конструкцию Попытка ... Исключение КонецПопытки без какого-либо кода внутри блока Исключение, произошедшая ошибка была просто проигнорирована платформой. Программа не вывела никаких предупреждений пользователю, не сделала запись в журнал регистрации и продолжила свое выполнение так, словно отправка файла завершилась успешно. Это классический пример "замалчивания" ошибок, который крайне затрудняет отладку.

Как правильно организовать выгрузку данных: пошаговое руководство

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

  1. Создадим временный файл на диске. Вместо работы со строками напрямую, мы должны физически сохранить сформированный XML во временную директорию операционной системы. Для этого воспользуемся встроенным методом ПолучитьИмяВременногоФайла, который вернет уникальный путь в системном каталоге.
  2. Запишем XML-данные во временный файл. Используем объекты ЗаписьТекста или ЗаписьXML для физического сохранения содержимого на локальный диск.
  3. Выполним подключение к FTP и передадим файл. Передадим в метод Записать реальный путь к сохраненному файлу на диске.
  4. Реализуем обработку ошибок. Обязательно добавим логирование в Журнал регистрации и информирование пользователя в блоке Исключение, чтобы не пропустить возможные сетевые сбои.
  5. Удалим временный файл. После успешной или неуспешной попытки отправки необходимо очистить временную папку, чтобы избежать засорения дискового пространства сервера или клиентского компьютера.

Реализация надежного алгоритма выгрузки на языке 1С

Рассмотрим подробнее исправленный и оптимизированный вариант процедуры. Этот код спроектирован с учетом всех правил работы с файловой системой и удаленными серверами в клиент-серверном режиме:


Процедура ОтправитьДокументXML(Документ)
    
    Если Не ОтправлятьНаFTP Тогда
        Возврат;
    КонецЕсли;
    
    // 1. Получаем уникальный путь для создания временного файла на диске
    ИмяВременногоФайлаXML = ПолучитьИмяВременногоФайла("xml");
    
    // 2. Записываем текстовые данные XML во временный файл на локальном диске
    Попытка
        ТекстXML = ПолучитьСтрокуXML(Документ);
        
        ЗаписьТекста = Новый ЗаписьТекста;
        // Используем кодировку UTF-8 без BOM или по требованию принимающего сервера
        ЗаписьТекста.Открыть(ИмяВременногоФайлаXML, КодировкаТекста.UTF8);
        ЗаписьТекста.ЗаписатьСтроку(ТекстXML);
        ЗаписьТекста.Закрыть();
    Исключение
        ВызватьИсключение "Не удалось сохранить XML-данные во временный файл на диске! Ошибка: " 
            + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
    КонецПопытки;
    
    // 3. Отправка файла на FTP-сервер с обработкой ошибок
    Попытка    
        // Указываем таймаут 30 секунд вместо 0, чтобы избежать вечного зависания процесса при сбоях сети
        FTP = Новый FTPСоединение(АдресFTPСервера, ПортFTPСервера, ЛогинFTP, ПарольFTP, Неопределено, ПассивныйРежимFTPСервера, 30);
        
        Если ЗначениеЗаполнено(ДиректорияFTPСервера) Тогда
            FTP.УстановитьТекущийКаталог(ДиректорияFTPСервера);
        Иначе
            FTP.УстановитьТекущийКаталог("/");
        КонецЕсли;
        
        ИмяФайлаНаФТП = "Order_" + Документ.Номер + "_" + Формат(Документ.Дата, "ДФ=dd.MM.yy") + ".xml";
        
        // Передаем ПУТЬ к локальному файлу на диске, а не сам текст XML
        FTP.Записать(ИмяВременногоФайлаXML, ИмяФайлаНаФТП);
        
        Сообщить("Файл успешно отправлен на FTP: " + ИмяФайлаНаФТП);
        
    Исключение
        // Логируем ошибку в системный Журнал регистрации для системного администратора
        ЗаписьЖурналаРегистрации("Выгрузка на FTP", 
            УровеньЖурналаРегистрации.Ошибка, 
            Документ.Метаданные(), 
            Документ.Ссылка, 
            ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
            
        // Выводим пользователю понятное сообщение об ошибке
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка при отправке файла на FTP: " 
            + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;
    
    // 4. Обязательное удаление временного файла после отправки (в блоке очистки ресурсов)
    Попытка
        ФайлЛокальный = Новый Файл(ИмяВременногоФайлаXML);
        Если ФайлЛокальный.Существует() Тогда
            УдалитьФайлы(ИмяВременногоФайлаXML);
        КонецЕсли;
    Исключение
        // Ошибку удаления временного файла фиксируем в фоне, чтобы не прерывать основной процесс
        ЗаписьЖурналаРегистрации("Очистка временных файлов", 
            УровеньЖурналаРегистрации.Предупреждение, 
            , 
            , 
            "Не удалось удалить временный файл " + ИмяВременногоФайлаXML + ". " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;
    
КонецПроцедуры

Дополнительные рекомендации по работе с FTP в среде 1С

Для создания действительно отказоустойчивых интеграционных механизмов необходимо учитывать важные технические особенности функционирования объекта FTPСоединение в платформе "1С:Предприятие":

Пассивный режим (Passive Mode)

Обязательно используйте пассивный режим работы FTP-сервера. Большинство современных корпоративных сетей защищены сетевыми экранами (Firewall) и используют механизмы трансляции сетевых адресов (NAT). В таких условиях активный режим передачи данных работать не будет: соединение установится, но при попытке получить список файлов или передать файл программа зависнет или завершится аварийно. Для активации пассивного режима передавайте значение Истина в шестой параметр конструктора FTPСоединение.

Ограничение времени ожидания (Таймаут)

Никогда не оставляйте таймаут равным нулю (без ограничений), особенно если выгрузка выполняется в фоновом режиме на сервере. Если удаленный сервер внезапно перестанет отвечать посреди сессии передачи данных, фоновое задание в 1С зависнет навсегда. Это может привести к исчерпанию ресурсов сервера 1С и блокировке базы данных. Рекомендуется устанавливать время ожидания в пределах от 15 до 60 секунд.

Различия между FTPS и SFTP

Важно понимать разницу между защищенными протоколами передачи данных. Объект FTPСоединение в платформе 1С поддерживает стандартный протокол FTP и протокол FTPS (FTP поверх SSL/TLS). Для активации шифрования необходимо передать объект ЗащищенноеСоединениеOpenSSL в качестве параметра конструктора.

Однако объект 1С не поддерживает работу по протоколу SFTP (SSH File Transfer Protocol, работающий через порт 22). Если ваш партнер требует использовать именно SFTP, вам придется использовать внешние консольные утилиты (например, WinSCP или curl) и запускать их через метод ЗапуститьПриложение().

Права доступа на сервере 1С

Если данный код выполняется на стороне сервера 1С (в клиент-серверном варианте работы), убедитесь, что у учетной записи службы сервера 1С (например, USR1CV8) есть полные права на чтение и запись в папку с временными файлами. Использование метода ПолучитьИмяВременногоФайла() гарантирует, что файл будет создан в разрешенной системной директории, что исключает ошибки доступа к файловой системе.

← На главную