При разработке в среде 1С:Предприятие часто возникает задача выгрузки данных в файлы. Если на клиенте это делается просто через диалоги выбора файла, то работа на сервере имеет свою специфику, связанную с файловой системой, правами доступа и методами оптимизации. В этой статье мы подробно разберем, как правильно сохранить файл на сервере, рассмотрим исходный пример кода и улучшим его, учитывая технические нюансы.
Рассмотрим ситуацию, описанную автором. Задача состоит в том, чтобы сформировать CSV-файл с данными (Номенклатура, Количество, Сумма) и сохранить его не на компьютере пользователя, а непосредственно на жестком диске сервера, где работает служба 1С.
Исходный код автора использует объект ТекстовыйДокумент (для более сложных трансформаций можно использовать модуль «Трансформер»). Давайте проанализируем логику:
&НаСервере
Процедура СерверНаСервере()
Документ = Новый ТекстовыйДокумент;
// Формируем заголовок
СтрНом = "Номенклатура;" + "КоличествоОстаток;" + "СуммаОстаток";
Документ.ДобавитьСтроку(СтрНом);
// Обходим выборку данных
Для каждого Строка из Объект.Результат Цикл
СтрНом = ПереводВСтроку(Строка.номенклатура) + ";" +
ПереводВСтроку(Строка.КоличествоОстаток) + ";" +
ПереводВСтроку(Строка.СуммаОстаток);
Документ.ДобавитьСтроку(СтрНом);
КонецЦикла;
// Здесь требуется код сохранения
КонецПроцедуры
Главный вопрос заключается в том, что написать после цикла, чтобы файл (будь то текст или выгрузка картинок номенклатуры) физически появился на диске сервера.
Самый простой ответ, который и был подсказан в обсуждении, заключается в использовании метода Записать. Важно понимать, что когда код выполняется внутри директивы &НаСервере, он "видит" файловую систему именно того компьютера, на котором запущен сервер 1С.
Следовательно, чтобы сохранить файл, достаточно указать локальный путь на сервере.
// Полный путь к файлу на диске СЕРВЕРА
ПутьКФайлу = "D:\Exchange\Report.csv";
// Сохранение
Документ.Записать(ПутьКФайлу);
Казалось бы, всё просто. Однако, при реализации этого подхода мы неизбежно столкнемся с рядом подводных камней, которые необходимо разобрать подробнее.
Давайте углубимся в технические детали, которые часто упускаются из виду, но являются критичными для стабильной работы механизма.
Это самая частая причина ошибок типа "Ошибка доступа к файлу" или "Каталог не найден". Серверный код 1С выполняется не от имени вашего доменного пользователя, а от имени служебной учетной записи, под которой запущена служба агента сервера 1С (чаще всего это USR1CV8 или системная запись Local System).
Мы должны убедиться, что:
D:\Exchange\), физически существует на сервере (аналогично тому, как происходит выгрузка внешних отчетов и обработок в каталог).USR1CV8 есть полные права (чтение и запись) на эту папку в свойствах безопасности Windows (или Linux).Важно: Сетевые диски, подключенные у вас в "Мой компьютер" (например, диск Z:), серверу обычно недоступны. Если нужно сохранить файл в сетевую папку, следует использовать UNC-пути, например: \\FileServer\Share\Report.csv, и убедиться, что у служебного пользователя сервера 1С есть доступ к этому сетевому ресурсу.
В исходном примере метод Записать используется без параметров кодировки. По умолчанию 1С часто сохраняет файлы в UTF-8. Если открыть такой CSV-файл в Excel (особенно старых версий) в Windows, вместо русских букв мы увидим некорректные символы ("кракозябры").
Чтобы файл корректно открывался в Excel, рекомендуется явно указывать кодировку ANSI (Windows-1251) или использовать конвертор из CSV в XLS.
// Сохраняем в кодировке Windows (ANSI)
Документ.Записать(ПутьКФайлу, КодировкаТекста.ANSI);
Современные сервера 1С часто работают на Linux. В Linux нет дисков C: или D:, а разделителем пути служит прямой слеш /, а не обратный \.
Чтобы ваш код был универсальным, лучше не прописывать разделители вручную, а использовать встроенную функцию платформы ПолучитьРазделительПути().
В обсуждении справедливо заметили: "Зачем создан ТекстовыйДокумент?". Давайте разберем этот момент. Объект ТекстовыйДокумент хранит всё содержимое файла в оперативной памяти. Если вам нужно выгрузить отчет на 500 000 строк, этот объект "съест" сотни мегабайт оперативной памяти сервера, что может привести к замедлению работы всей системы.
Более правильным и производительным способом для записи файлов является использование объекта ЗаписьТекста. Он пишет данные в файл потоком, строка за строкой, практически не расходуя оперативную память.
Давайте перепишем код автора, используя этот оптимальный подход:
&НаСервере
Процедура СохранитьФайлНаСервереОптимально()
// Формируем путь. Лучше вынести путь в константу или настройку
ПутьКФайлу = "D:\Exchange\Report.csv";
// Создаем объект записи.
// Указываем кодировку ANSI для корректного открытия в Excel под Windows
Запись = Новый ЗаписьТекста(ПутьКФайлу, КодировкаТекста.ANSI);
// Формируем и записываем заголовок
Заголовок = "Номенклатура;Количество;Сумма" + Символы.ПС;
Запись.Записать(Заголовок);
// Обходим выборку данных
Для каждого СтрокаДанных Из Объект.Результат Цикл
// Формируем строку CSV.
// Важно: экранирование спецсимволов (если в названии есть точка с запятой)
// Для простоты примера используем упрощенную склейку
СтрФайла = Строка(СтрокаДанных.Номенклатура) + ";" +
XMLСтрока(СтрокаДанных.КоличествоОстаток) + ";" +
XMLСтрока(СтрокаДанных.СуммаОстаток) + Символы.ПС;
// Записываем строку сразу в файл на диск
Запись.Записать(СтрФайла);
КонецЦикла;
// Обязательно закрываем файл, чтобы сохранить изменения и освободить блокировку
Запись.Закрыть();
КонецПроцедуры
Подводя итог, выделим основные шаги для успешного сохранения файла на сервере:
/opt/1c/tmp/ для Linux или C:\Temp\ для Windows).ТекстовыйДокумент, для больших отчетов — только ЗаписьТекста.КодировкаТекста.ANSI для CSV под Windows).Применяя эти рекомендации, вы сможете создавать надежные механизмы выгрузки данных, которые не будут перегружать сервер и вызывать ошибки доступа.