При разработке механизмов обмена данными или архивации часто возникает задача программного копирования целых директорий вместе с вложенными файлами. Однако на практике программисты 1С часто сталкиваются с ситуацией, когда процедура отрабатывает без видимых ошибок, структура папок в целевом каталоге создается, но сами файлы внутри них отсутствуют. Рассмотрим подробно, почему это происходит, проанализируем типичные ошибки в коде и разберем системные факторы, влияющие на работу с файловой системой.
Рассмотрим стандартную ситуацию: нам необходимо перенести содержимое одного каталога в другой. Чаще всего для этого используется рекурсивная процедура, которая обходит дерево папок. Посмотрим на пример кода, который изначально предложил автор темы:
&НаСервере
Процедура СкопироватьКаталог(КаталогИсточник, КаталогПриемник, ПерезаписатьФайл = Ложь)
МассивФайловДляКопирования = НайтиФайлы(КаталогИсточник, "*.*");
Для каждого ФайлДляКопирования Из МассивФайловДляКопирования Цикл
НовыйПуть = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(КаталогПриемник) + ФайлДляКопирования.Имя;
НовыйПуть = НРег(НовыйПуть);
Если ФайлДляКопирования.ЭтоКаталог Тогда
// Создаем папку в приемнике
СоздатьКаталог(НовыйПуть);
// Рекурсивно заходим внутрь
СкопироватьКаталог(ФайлДляКопирования.ПолноеИмя, НовыйПуть, ПерезаписатьФайл);
Иначе
// Пытаемся скопировать файл
КопироватьФайл(ФайлДляКопирования.ПолноеИмя, НовыйПуть);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
На первый взгляд, логика верна. Функция НайтиФайлы получает список всех объектов, ЭтоКаталог разделяет папки и файлы, а рекурсивный вызов позволяет обрабатывать любую глубину вложенности. Однако именно здесь кроются несколько подводных камней.
Выясним основную причину, на которую указал автор в ходе отладки. Проблема часто заключается в том, что переменная НовыйПуть при определенных условиях перестает содержать имя файла. Если при рекурсивном вызове в КаталогПриемник передается путь, который уже содержит ошибочные разделители или некорректно обработан функцией НРег, метод КопироватьФайл может воспринять целевой путь как директорию, а не как имя файла.
Важно помнить: метод КопироватьФайл(Источник, Приемник) ожидает в параметре Приемник полный путь, включая имя файла и расширение. Если передать туда только путь к папке, копирование не произойдет или вызовет ошибку доступа.
Проанализируем совет из обсуждения: разделение одного цикла на два. Это стратегически верный подход. В первом цикле мы создаем всю структуру подкаталогов, а во втором — переносим файлы. Это гарантирует, что на момент вызова КопироватьФайл целевая папка уже гарантированно существует в файловой системе.
Разберем доработанный пример кода:
&НаСервере
Процедура СкопироватьКаталог(КаталогИсточник, КаталогПриемник, ПерезаписатьФайл = Ложь)
МассивФайлов = НайтиФайлы(КаталогИсточник, "*.*");
// Первый проход: обрабатываем только каталоги
Для каждого Объект Из МассивФайлов Цикл
Если Объект.ЭтоКаталог Тогда
НоваяПапка = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(КаталогПриемник) + Объект.Имя;
СоздатьКаталог(НоваяПапка);
// Рекурсия для вложенных папок
СкопироватьКаталог(Объект.ПолноеИмя, НоваяПапка, ПерезаписатьФайл);
КонецЕсли;
КонецЦикла;
// Второй проход: копируем только файлы
Для каждого Объект Из МассивФайлов Цикл
Если НЕ Объект.ЭтоКаталог Тогда
ЦелевойФайл = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(КаталогПриемник) + Объект.Имя;
Попытка
КопироватьФайл(Объект.ПолноеИмя, ЦелевойФайл);
Исключение
Сообщить("Ошибка копирования: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Если код выполняется в контексте &НаСервере, необходимо учитывать, что операции с файлами выполняет не текущий пользователь компьютера, а учетная запись, от имени которой запущена служба "1С:Предприятие 8" (по умолчанию это USR1CV8).
Рассмотрим критические моменты, связанные с правами:
\\Server\Share), локальная системная учетная запись сервера 1С не сможет туда достучаться. В этом случае службу 1С нужно запускать от имени доменного пользователя с правами на эти папки.УстановитьТолькоЧтение(Ложь). Это полезная практика, но она работает только с атрибутами файла. Если доступ ограничен на уровне NTFS (вкладка "Безопасность" в свойствах папки), 1С не сможет скопировать файл, даже если программно снимет атрибут Read Only.Проанализируем использование НРег() для приведения путей к нижнему регистру. В операционных системах семейства Windows регистр имен файлов обычно не имеет значения. Однако, если ваш сервер 1С работает под управлением Linux, использование НРег() может стать фатальной ошибкой. В Linux пути /Home/Data.txt и /home/data.txt — это разные объекты. Мы рекомендуем сохранять оригинальный регистр имен файлов, получаемый из свойства ФайлДляКопирования.Имя.
Чтобы понять, почему файл не копируется, выполним следующие шаги:
КопироватьФайл добавим проверку Объект.Существует(). Это исключит попытки работы с "призрачными" файлами (например, временными файлами, которые исчезли в процессе работы цикла)."*.*" в функции НайтиФайлы лучше использовать пустую строку или просто "*". Маска с точкой может проигнорировать файлы без расширения в некоторых операционных системах.ФайловаяСистема. Например, ФайловаяСистема.КопироватьФайл(). Эти методы содержат более продвинутую обработку ошибок и могут автоматически создавать цепочку недостающих папок в пути назначения.MAX_PATH (260 символов). При глубокой вложенности папок итоговый путь может превысить этот лимит, и 1С выдаст ошибку, хотя визуально пути будут казаться правильными.Подводя итог, можно сказать, что "мистическое" исчезновение файлов при копировании чаще всего вызвано либо банальной ошибкой конкатенации строк (потеря имени файла в конце пути), либо ограничениями прав доступа серверной учетной записи. Тщательная отладка с проверкой каждого значения НовыйПуть в табло обычно позволяет быстро локализовать место, где строка пути формируется некорректно.