Перемещение файлов во встроенном языке 1С: ПереместитьФайл, COM и сетевые папки

· 11 мин

Содержание

Чтобы переместить файл в 1С программно, вызовите метод глобального контекста ПереместитьФайл(ИмяФайлаИсточника, ИмяФайлаПриемника). Он переносит файл и при необходимости меняет его имя за одну операцию. На клиенте с асинхронным режимом используйте ПереместитьФайлАсинх (платформа 8.3.18 и выше) или НачатьПеремещениеФайла на более ранних версиях.

Сам вызов — одна строка. Проблемы начинаются вокруг него: нет каталога-приёмника, файл с таким именем уже лежит, сетевая папка не видна службе сервера, код выполняется не на том компьютере. Каждый из этих случаев решается парой строк кода, если знать, где искать.

Метод ПереместитьФайл: синтаксис и базовый пример

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

Источник = "C:\Обмен\Входящие\order_001.xml";
Приемник = "C:\Обмен\Архив\order_001.xml";

ПереместитьФайл(Источник, Приемник);

Что важно знать о методе:

  • 📍 Где работает. Сервер, толстый клиент, тонкий клиент, внешнее соединение. В веб-клиенте — только с расширением работы с файлами и с учётом режима синхронных вызовов.
  • 📍 На каком компьютере. Пути считаются на той машине, где выполняется код. &НаСервере — это диск сервера 1С, &НаКлиенте — диск пользователя.
  • 📍 Каталоги. Методом можно переносить и папку целиком, но на практике надёжнее работать с файлами по одному: так проще ловить ошибки.
  • 📍 Ошибки. Метод ничего не возвращает. Неудача — это исключение, поэтому вызов всегда оборачивают в Попытка … Исключение.

Для переименования файла отдельного метода нет. Переименование — это тот же ПереместитьФайл в пределах одного каталога: ПереместитьФайл(Каталог + "old.txt", Каталог + "new.txt").

Разделитель пути

Не склеивайте пути через жёсткий "\", если код может попасть на сервер под Linux. Платформа отдаёт правильный разделитель сама:

Разделитель = ПолучитьРазделительПути();
Приемник = КаталогАрхива + Разделитель + ИмяФайла;

В конфигурациях на БСП для этого же есть ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(Путь) — он добавит слеш, только если его нет.

Подготовка к перемещению: проверки, каталог, имя

Голый ПереместитьФайл в рабочем коде почти не встречается. Перед ним стоят три проверки. Они снимают большую часть падений обработки.

  1. Источник существует и это файл. Объект Файл даёт Существует() и ЭтоФайл().
  2. Каталог-приёмник есть. Если нет — создаём его через СоздатьКаталог(). Метод создаёт всю цепочку вложенных папок.
  3. Имя в приёмнике свободно. Не полагайтесь на то, как платформа поведёт себя при занятом имени. Решите это явно: удалить старый файл, пропустить или выбрать новое имя.

Функция, которую можно класть в общий модуль:

// Возвращает полный путь к перемещённому файлу или пустую строку при ошибке.
Функция ПереместитьФайлБезопасно(ПутьИсточника, КаталогПриемника, Заменять = Ложь) Экспорт

    ФайлИсточник = Новый Файл(ПутьИсточника);
    Если Не ФайлИсточник.Существует() Или Не ФайлИсточник.ЭтоФайл() Тогда
        Возврат "";
    КонецЕсли;

    КаталогОбъект = Новый Файл(КаталогПриемника);
    Если Не КаталогОбъект.Существует() Тогда
        СоздатьКаталог(КаталогПриемника);
    КонецЕсли;

    ПутьПриемника = КаталогПриемника + ПолучитьРазделительПути() + ФайлИсточник.Имя;
    ФайлПриемник = Новый Файл(ПутьПриемника);

    Если ФайлПриемник.Существует() Тогда
        Если Заменять Тогда
            УдалитьФайлы(ПутьПриемника);
        Иначе
            ПутьПриемника = КаталогПриемника + ПолучитьРазделительПути()
                + ФайлИсточник.ИмяБезРасширения + "_"
                + Формат(ТекущаяДатаСеанса(), "ДФ=yyyyMMdd_HHmmss")
                + ФайлИсточник.Расширение;
        КонецЕсли;
    КонецЕсли;

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

    Возврат ПутьПриемника;

КонецФункции

Свойство Расширение объекта Файл возвращает расширение вместе с точкой (.xml), поэтому точку при склейке добавлять не нужно.

Метка времени с точностью до секунды не спасает, если за секунду приходит несколько файлов с одинаковым именем. Для потоков обмена добавляйте к имени счётчик или Новый УникальныйИдентификатор().

Атомарная передача файла другой программе

Частая задача: 1С выгружает файл в папку, а другая система (сканер папки, банк-клиент, служба обмена) его подхватывает. Если писать сразу под итоговым именем, внешняя программа может схватить недописанный файл.

Приём практика:

  1. Записать файл в ту же папку под временным именем, например order_001.xml.tmp.
  2. Дописать и закрыть его полностью.
  3. Переименовать через ПереместитьФайл в order_001.xml.

Переименование внутри одного тома происходит мгновенно. Внешняя программа видит файл уже целым.

Перемещение файлов по маске и пакетом

Для разбора каталога обмена нужен перенос сразу многих файлов. Список собирает НайтиФайлы(Каталог, Маска, ИскатьВПодкаталогах), а дальше — цикл:

Найденные = НайтиФайлы("D:\Обмен\Входящие", "*.xml", Ложь);

Перемещено = 0;
Для Каждого ФайлОбмена Из Найденные Цикл
    Если Не ФайлОбмена.ЭтоФайл() Тогда
        Продолжить;
    КонецЕсли;
    Результат = ПереместитьФайлБезопасно(ФайлОбмена.ПолноеИмя, "D:\Обмен\Обработанные");
    Если ЗначениеЗаполнено(Результат) Тогда
        Перемещено = Перемещено + 1;
    КонецЕсли;
КонецЦикла;

Сообщить(СтрШаблон("Перемещено файлов: %1 из %2",
    Формат(Перемещено, "ЧН=0; ЧГ=0"), Формат(Найденные.Количество(), "ЧН=0; ЧГ=0")));

Пара замечаний из практики:

  • 🔹 НайтиФайлы возвращает массив объектов Файл, а не строк. Путь берите из ПолноеИмя.
  • 🔹 Перемещайте файл после успешной загрузки его содержимого в базу, а не до. Иначе при ошибке загрузки файл уже окажется в архиве, и его никто не обработает.
  • 🔹 Для файлов с ошибкой заведите отдельную папку Ошибки. Так входящий каталог не забивается «вечными» файлами, которые падают при каждом запуске регламентного задания.
  • 🔹 Маска поддерживает * и ?. Для нескольких расширений вызовите НайтиФайлы несколько раз.

Перемещение через COM-объект FileSystemObject

На Windows есть альтернатива — стандартный компонент Scripting.FileSystemObject. Его создают через COMОбъект на сервере или на Windows-клиенте:

FSO = Новый COMОбъект("Scripting.FileSystemObject");

Если FSO.FileExists("C:\Обмен\out.xml") Тогда
    FSO.MoveFile("C:\Обмен\out.xml", "\\fileserver\exchange\out.xml");
КонецЕсли;

Особенности MoveFile:

  • 🧩 Если приёмник уже существует, метод выдаёт ошибку. Замены «поверх» нет — сначала DeleteFile.
  • 🧩 Путь приёмника, оканчивающийся на \, трактуется как папка: файл переедет в неё под своим именем.
  • 🧩 Источник может содержать маску: FSO.MoveFile("C:\Обмен\*.xml", "D:\Архив\") перенесёт все XML одной строкой.
  • 🧩 Для копирования с перезаписью есть CopyFile(Источник, Приемник, Истина), для папок — MoveFolder.

Когда какой способ брать:

СпособКогда подходитОграничения
ПереместитьФайлПочти всегда, основной вариантНет масок, занятое имя проверяйте сами
ПереместитьФайлАсинх / НачатьПеремещениеФайлаКлиентский код, веб-клиентНужен асинхронный стиль кода
FileSystemObject.MoveFileПакетный перенос по маске на WindowsТолько Windows, не работает на Linux-сервере и в веб-клиенте
Копирование + удалениеПеренос между томами и по сети, когда важна проверкаДве операции, нужен контроль результата

COM-вариант привязывает код к Windows. Если сервер 1С когда-нибудь переедет на Linux, все вызовы COMОбъект придётся переписывать. Без веской причины берите встроенные методы.

Как переместить файл в сетевую папку: пути и права

Сетевые пути — главный источник ошибок «на сервере не работает , а у меня работает».

UNC вместо буквы диска

Пишите путь в формате \\fileserver\exchange\in\file.xml. Подключённые буквы дисков (Z:\) существуют только в сеансе конкретного пользователя Windows. Служба сервера 1С их не видит, даже если на сервере под администратором диск подключён.

Чьими правами работает код

Где выполняется кодЧьими правами идёт доступ к файлам
&НаСервере, клиент-серверная базаУчётная запись службы агента сервера 1С (по умолчанию USR1CV8)
&НаСервере, файловая базаПользователь Windows, запустивший 1С
&НаКлиенте, тонкий или толстый клиентПользователь Windows на компьютере клиента
Регламентное заданиеУчётная запись службы сервера 1С

Отсюда рабочий порядок для клиент-серверной базы:

  1. Узнать, под какой учётной записью запущена служба агента сервера 1С (оснастка «Службы» Windows, вкладка «Вход в систему»).
  2. Если это локальная учётная запись — перевести службу на доменную, иначе файловый сервер её не узнает.
  3. Выдать этой записи права на общую папку и на файловую систему: чтение и удаление в источнике, запись в приёмнике.
  4. Перезапустить службу в нерабочее время.

Перезапуск службы агента сервера 1С обрывает все сеансы пользователей и прерывает регламентные задания. Делайте его вечером или в согласованное окно и предупредите пользователей заранее.

Сервер на Linux

На Linux сетевую папку сначала монтируют в файловую систему (например, через cifs в /mnt/exchange), а в коде пишут уже локальный путь /mnt/exchange/in/file.xml. Права проверяют для пользователя, от которого работает сервер 1С (обычно usr1cv8).

Перенос между томами и по сети

Когда источник и приёмник на разных дисках или на разных машинах, перемещение по сути превращается в копирование с удалением. При обрыве сети на середине можно получить обрезанный файл в приёмнике. Надёжнее сделать это руками и сверить размер:

КопироватьФайл(Источник, Приемник);

Если (Новый Файл(Приемник)).Размер() = (Новый Файл(Источник)).Размер() Тогда
    УдалитьФайлы(Источник);
Иначе
    ВызватьИсключение "Размер копии не совпал с исходным файлом: " + Источник;
КонецЕсли;

Перемещение файлов на клиенте, в веб-клиенте и на сервере

Директива компиляции определяет, чей диск вы трогаете. Это ключ к большинству вопросов «файл не находится».

Сервер

Код &НаСервере или в общем модуле с флагом «Сервер» видит только диски сервера 1С. Пользовательский рабочий стол оттуда недоступен. Обычный синхронный ПереместитьФайл здесь — правильный выбор.

Тонкий клиент и асинхронные методы

В конфигурациях, где запрещены синхронные вызовы (свойство конфигурации «Режим использования синхронных вызовов расширений платформы и внешних компонент»), на клиенте используйте асинхронный вариант:

&НаКлиенте
Асинх Процедура ПереместитьВыгрузку(Команда)

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

КонецПроцедуры

Конструкция Асинх/Ждать доступна с платформы 8.3.18. На платформах с номером ниже 8.3.18 используйте НачатьПеремещениеФайла с ОписаниеОповещения; порядок параметров процедуры-обработчика сверьте в синтакс-помощнике своей платформы.

Веб-клиент

Браузер сам по себе не даёт доступа к дискам пользователя. Перед любой работой с локальными файлами нужно подключить расширение работы с файлами:

&НаКлиенте
Асинх Процедура ПереместитьВВебКлиенте(Команда)

    Подключено = Ждать ПодключитьРасширениеРаботыСФайламиАсинх();
    Если Не Подключено Тогда
        НачатьУстановкуРасширенияРаботыСФайлами();
        Возврат;
    КонецЕсли;

    Ждать ПереместитьФайлАсинх(ПутьИсточника, ПутьПриемника);

КонецПроцедуры

При первом запуске пользователь увидит предложение установить расширение . Без него код упадёт.

Файл нужно перенести с клиента на сервер

ПереместитьФайл не умеет «переносить между компьютерами». Схема такая: на клиенте прочитать файл в ДвоичныеДанные и положить во временное хранилище, на сервере достать их и записать на диск, затем удалить исходный файл на клиенте.

&НаКлиенте
Процедура ОтправитьНаСервер(Команда)
    Данные = Новый ДвоичныеДанные(ПутьНаКлиенте);
    Адрес = ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор);
    Если ЗаписатьНаСервере(Адрес, "order_001.xml") Тогда
        УдалитьФайлы(ПутьНаКлиенте);
    КонецЕсли;
КонецПроцедуры

&НаСервере
Функция ЗаписатьНаСервере(Адрес, ИмяФайла)
    Данные = ПолучитьИзВременногоХранилища(Адрес);
    Данные.Записать("D:\Обмен\Входящие\" + ИмяФайла);
    УдалитьИзВременногоХранилища(Адрес);
    Возврат Истина;
КонецФункции

Исходный файл удаляется только после того, как сервер подтвердил запись. Если запись упадёт, исключение прервёт процедуру раньше УдалитьФайлы, и файл у пользователя останется.

Безопасный режим

Внешние обработки и расширения конфигурации , подключённые в безопасном режиме, к файловой системе не допускаются. Тогда ПереместитьФайл выдаст ошибку о недостатке прав, хотя путь верный. Решение — запуск без безопасного режима или профиль безопасности с разрешением на нужный каталог; это настраивает администратор базы.

Обработка ошибок при перемещении файла

Перемещение падает исключением, а не возвращает Ложь. Отсюда правило: каждый вызов в Попытка, текст ошибки — в журнал регистрации, а не только пользователю. Регламентное задание сообщения на экран не покажет.

Типовой обработчик:

Попытка
    ПереместитьФайл(Источник, Приемник);
Исключение
    ТекстОшибки = ОписаниеОшибки();
    ЗаписьЖурналаРегистрации("Обмен.ПеремещениеФайла",
        УровеньЖурналаРегистрации.Ошибка, , , 
        СтрШаблон("%1 -> %2: %3", Источник, Приемник, ТекстОшибки));
    // решаем: пропустить файл, отправить в папку Ошибки или прервать весь обмен
КонецПопытки;

Что обычно стоит за ошибкой:

Диагностика: выберите симптом

Повтор при занятом файле

Если файл кладёт внешняя программа, он может быть ещё открыт на запись в момент обработки. Не крутите повтор в цикле без паузы на сервере. Правильнее оставить файл на месте и забрать его при следующем запуске регламентного задания — через минуту он уже будет закрыт.

Как ускорить и упростить работу с файлами

Несколько правил, которые снимают проблемы до их появления:

  • ✅ Один каталог — одна роль. Входящие, Обработанные, Ошибки. Код не должен перебирать архив при каждом запуске.
  • ✅ Не держите в папке десятки тысяч файлов. НайтиФайлы по такому каталогу работает заметно дольше. Раскладывайте архив по подпапкам с датой: Архив\2026-10\.
  • ✅ Закрывайте потоки. После ЧтениеXML, ЧтениеТекста, ЗаписьТекста вызывайте Закрыть() до перемещения. Иначе файл остаётся занятым процессом 1С.
  • ✅ Временные файлы — через платформу. ПолучитьИмяВременногоФайла("xml") даёт уникальное имя в каталоге временных файлов. В типовых на БСП есть общий модуль ФайловаяСистема с обёртками для временных файлов и каталогов — загляните в него, прежде чем писать свои.
  • ✅ Пути — в настройки. Каталоги обмена храните в константах или регистре сведений, а не строками в коде. При переезде сервера правится одна запись.
  • ✅ Логируйте успех тоже. Одна строка в журнале регистрации на каждый перенесённый файл потом экономит время на разборе «куда делась выгрузка».

Частые вопросы

Можно ли переместить файл с перезаписью одной командой?
Встроенного параметра «заменить» у ПереместитьФайл нет. Явно удалите существующий файл в приёмнике через УдалитьФайлы, затем переместите.
Чем ПереместитьФайл отличается от КопироватьФайл с удалением?
В пределах одного тома перемещение мгновенное и не требует места под копию. Копирование с удалением полезно при переносе по сети, когда нужно сверить результат до удаления оригинала.
Как переместить всю папку с вложенными файлами?
Надёжный способ — НайтиФайлы с флагом поиска в подкаталогах, воссоздание структуры через СоздатьКаталог и перенос файлов по одному. На Windows можно использовать MoveFolder у FileSystemObject.
Почему регламентное задание не видит сетевой диск Z:?
Задание выполняется на сервере под учётной записью службы 1С, у которой нет подключённых дисков. Укажите UNC-путь вида \сервер\папка.
Как убедиться, что файл действительно перемещён?
После вызова проверьте два условия: Новый Файл(Приемник).Существует() возвращает Истина, а для источника — Ложь. Это стоит делать в обменах, где потеря файла критична.