При активной работе с внешними хранилищами, например, при выгрузке фотографий товаров на сайт, разработчики часто сталкиваются с ситуацией, когда стандартный объект 1С FTPСоединение начинает вести себя непредсказуемо. Типичный сценарий: в папке на сервере накопилось несколько десятков тысяч файлов, и при попытке удалить один из них встроенными средствами платформы возникает исключение "Ошибка доступа к ресурсу. Путь не найден", хотя файл гарантированно существует. В этой статье мы подробно разберем причины такого поведения и рассмотрим эффективные способы решения проблемы.
Когда мы вызываем метод FTP.Удалить(), платформа 1С выполняет ряд внутренних операций. Важно понимать, что текст ошибки, который мы видим в ОписаниеОшибки(), формируется на основе ответа FTP-сервера, но интерпретируется самой платформой. Появление лишнего слэша в конце пути (например, /file.jpg/) — это часто внутренняя особенность 1С, сигнализирующая о том, что объект не был идентифицирован в текущем контексте сессии.
Основная причина кроется в лимитах листинга. Большинство FTP-серверов (таких как ProFTPD или Pure-FTPd) по умолчанию имеют ограничение на количество отображаемых файлов в одной директории (обычно это 5000 или 10000 объектов). Если в каталоге 70 000 файлов, команда НайтиФайлы() вернет только первые 9999. Метод Удалить(), хотя и принимает прямой путь, может давать сбой, если сервер слишком долго ищет конкретный файл в огромном неиндексированном списке или если платформа 1С пытается предварительно проверить существование файла через механизмы, подверженные этому лимиту.
Рассмотрим стандартный подход, который часто дает сбой при большом количестве файлов. Многие разработчики передают полный путь к файлу в одну строку. Однако объект FTPСоединение работает стабильнее, если разделять путь к каталогу и маску (имя) файла. Проанализируем пример кода, который повышает вероятность успешного выполнения операции:
// Неправильно или менее надежно:
// FTP.Удалить("/Parts/my_image_guid.jpg");
// Более надежный вариант с разделением параметров:
ПутьККаталогу = "/Parts/";
ИмяФайла = "3169d447-4c45-11e8-a198-38d54777b870_025bbb21-ac1a-11e8-a298-38d54777b870.jpg";
Попытка
// Используем второй синтаксис метода: Удалить(Путь, Маска)
FTP.Удалить(ПутьККаталогу, ИмяФайла);
Сообщить("Файл успешно удален: " + ИмяФайла);
Исключение
Сообщить("Не удалось удалить файл: " + ОписаниеОшибки());
КонецПопытки;
Важный момент: Перед массовым удалением в цикле обязательно убедитесь, что установлено свойство ПассивныйРежим = Истина. В активном режиме при большом количестве запросов брандмауэр сервера может блокировать новые входящие соединения для передачи данных, что приведет к ложным ошибкам доступа.
Если мы храним 70 000 и более файлов в одной папке, мы неизбежно столкнемся с деградацией производительности самой файловой системы сервера. Самый эффективный способ решить проблему — распределить файлы по подкаталогам. Рассмотрим, как это сделать на основе GUID товара или уникального идентификатора файла.
Разберем алгоритм создания вложенной структуры. Вместо того чтобы класть файл напрямую в /Parts/, мы будем использовать первые символы имени файла для создания подпапок. Например, для файла 3169d447-....jpg путь будет выглядеть так: /Parts/31/69/3169d447-....jpg.
Функция ПолучитьИерархическийПуть(ИмяФайла)
// Извлекаем первые два уровня для подпапок
Уровень1 = Лев(ИмяФайла, 2);
Уровень2 = Сред(ИмяФайла, 3, 2);
// Формируем относительный путь
Возврат Уровень1 + "/" + Уровень2 + "/";
КонецФункции
// Пример использования при удалении
ИмяФайла = "3169d447-4c45-11e8-a198-38d54777b870.jpg";
ОтносительныйПуть = ПолучитьИерархическийПуть(ИмяФайла); // Результат: "31/69/"
ПолныйПутьНаСервере = "/Parts/" + ОтносительныйПуть;
FTP.Удалить(ПолныйПутьНаСервере, ИмяФайла);
Этот подход гарантирует, что в каждой конечной папке будет не более 256 файлов (если использовать шестнадцатеричные символы GUID), что мгновенно снимает проблему лимитов листинга и ускоряет работу FTPСоединение в десятки раз.
Если изменить структуру хранения на сервере невозможно, а штатный клиент 1С продолжает "терять" файлы, стоит рассмотреть использование более мощных инструментов. Внешние утилиты, такие как WinSCP или cURL, работают с протоколом FTP на более низком уровне и умеют корректно обрабатывать огромные списки файлов.
Проанализируем ситуацию использования WinSCP через COM-объект. Это решение позволяет избежать ограничений 1С на объем возвращаемых данных:
// Пример логики работы через COM-объект WinSCP
Попытка
Сессия = Новый COMОбъект("WinSCP.Session");
ОпцииСессии = Новый COMОбъект("WinSCP.SessionOptions");
ОпцииСессии.Protocol = 1; // FTP
ОпцииСессии.HostName = "ftp.myserver.ru";
ОпцииСессии.UserName = "admin";
ОпцииСессии.Password = "password";
Сессия.Open(ОпцииСессии);
// Удаление файла напрямую по полному пути
РезультатУдаления = Сессия.RemoveFiles("/Parts/my_file.jpg");
РезультатУдаления.Check(); // Проверка на ошибки
Сессия.Dispose();
Исключение
Сообщить("Ошибка WinSCP: " + ОписаниеОшибки());
КонецПопытки;
Также эффективным методом является запуск консольной утилиты curl. Мы можем сформировать пакетный файл (скрипт) со списком всех имен файлов, которые нужно удалить, и запустить его одной командой. Это минимизирует количество переподключений и ускоряет процесс.
Иногда возникает ситуация: 1С сообщает, что код удаления выполнен успешно (исключение не сработало), но файл остается на сервере. Рассмотрим, почему это происходит:
DELE пометит его как удаленный, но физически он исчезнет только после закрытия всех дескрипторов.Для диагностики таких случаев мы рекомендуем всегда анализировать логи самого FTP-сервера (например, файл xferlog), где фиксируется реальный результат выполнения команды DELE.
Для стабильной работы с файлами на удаленном хостинге в 1С следует придерживаться следующих правил:
FTP.Удалить(Путь, ИмяФайла) работает надежнее, чем передача полной строки.HTTPСоединение и методы POST/DELETE зачастую оказывается более стабильной и современной альтернативой устаревшему протоколу FTP.Соблюдение этих архитектурных принципов позволит вам избежать ошибок "Путь не найден" и обеспечит высокую скорость работы вашей системы обмена данными.