В процессе разработки в среде 1С:Предприятие 8.3 программисты часто сталкиваются с задачей сохранения печатных форм (табличных документов) во внешние файлы с последующим их преобразованием в двоичные данные. Однако иногда привычный код внезапно выдает исключение: «Ошибка при вызове конструктора (ДвоичныеДанные): Недопустимое значение параметра (параметр номер '1')». Проанализируем, почему это происходит, и разберем наиболее надежные способы решения этой задачи.
Рассмотрим типичный фрагмент кода, который может привести к ошибке. В данном примере мы пытаемся программно сформировать имя файла на основе представления документа, сохранить табличный документ на диск и прочитать его обратно для дальнейшей обработки (например, для отправки по почте или записи в справочник «Присоединенные файлы»):
ИмяФайла = ИмяТабдок + " " + СокрЛП(СтрЗаменить(МассивСсылок[0].Ссылка, "(не проведен)","")) + ".PDF";
КаталогВременныхФайлов = КаталогВременныхФайлов();
ПолноеИмяФайла = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(КаталогВременныхФайлов, ИмяФайла);
ТабДок.Записать(ПолноеИмяФайла, ТипФайлаТабличногоДокумента.PDF);
мФайл = Новый ДвоичныеДанные(ПолноеИмяФайла);
Проанализируем ситуацию через отладчик. Если переменная ПолноеИмяФайла содержит строку вида "E:\Temp\Заказ поставщику 0001 от 18.07.2022 13:08:34.PDF", мы увидим проблему. В операционных системах семейства Windows символ двоеточия : является зарезервированным. Он используется для обозначения логических дисков или альтернативных потоков данных (ADS). Использование двоеточия в основной части имени файла запрещено.
Выясним, почему метод Записать() табличного документа может не выдавать ошибку сразу. В некоторых версиях платформы метод Записать() при наличии двоеточия в середине пути ведет себя коварно: он либо «обрезает» имя файла до первого недопустимого символа, либо создает файл, который фактически недоступен для стандартных методов чтения. В итоге, когда управление переходит к конструктору Новый ДвоичныеДанные(ПолноеИмяФайла), система пытается найти файл по некорректному пути и возвращает ошибку «Недопустимое значение параметра».
Первый и самый очевидный способ исправления — это очистка имени файла от символов, которые файловая система считает недопустимыми. К таким символам относятся: \ / : * ? " < > |. Рассмотрим, как правильно подготовить строку имени файла.
Если в вашей конфигурации используется БСП (Библиотека стандартных подсистем), лучше всего воспользоваться готовой функцией. Разберем пример ее вызова:
// Очищаем имя от всех запрещенных символов
ИмяФайла = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(ИмяФайла, "");
Если же вы пишете код в самописной конфигурации без БСП, можно реализовать простую замену самостоятельно. Проанализируем следующий пример:
НедопустимыеСимволы = "\/:*?""<>|";
Для Индекс = 1 По СтрДлина(НедопустимыеСимволы) Цикл
СимволЗамены = Сред(НедопустимыеСимволы, Индекс, 1);
ИмяФайла = СтрЗаменить(ИмяФайла, СимволЗамены, "");
КонецЦикла;
Важный совет: При формировании имен файлов, содержащих дату, всегда используйте формат без двоеточий и точек. Например, формат ГГГГММДДЧЧММСС (20220718130834) не только безопасен, но и позволяет корректно сортировать файлы в папке по алфавиту в хронологическом порядке.
Зачем нагружать дисковую подсистему сервера и беспокоиться о правах доступа к временным папкам или корректности имен файлов? Начиная с версии платформы 8.3.9, в 1С реализован механизм работы с потоками. Это позволяет выполнить операцию полностью в оперативной памяти.
Рассмотрим подробнее этот алгоритм. Мы создаем объект ПотокВПамяти, записываем в него данные табличного документа и сразу получаем ДвоичныеДанные, не создавая ни одного файла на диске.
Разберем этот процесс по шагам в коде:
// 1. Создаем поток в оперативной памяти
ПотокВПамяти = Новый ПотокВПамяти();
// 2. Записываем табличный документ в этот поток в формате PDF
// Обратите внимание: метод поддерживает запись в поток начиная с версии 8.3.9
ТабДок.Записать(ПотокВПамяти, ТипФайлаТабличногоДокумента.PDF);
// 3. Закрываем поток и получаем результат в виде объекта ДвоичныеДанные
ДвоичныеДанныеФайла = ПотокВПамяти.ЗакрытьИПолучитьДвоичныеДанные();
// Теперь ДвоичныеДанныеФайла можно передать на сервер, записать в ИБ или отправить клиенту
Преимущества данного метода:
Temp.КаталогВременныхФайлов() и заботиться об уникальности имен при одновременной работе нескольких пользователей.Посмотрим на ситуацию со стороны архитектуры «клиент-сервер». Если вы формируете файл в коде на стороне сервера (например, в общем модуле), то функция КаталогВременныхФайлов() вернет путь к временной папке пользователя, под которым запущен агент службы 1С (обычно USR1CV8). Если после этого вы попытаетесь обратиться к этому файлу с клиента, вы получите ошибку, так как у клиентской машины нет доступа к локальным папкам сервера.
Именно поэтому использование объекта ДвоичныеДанные в связке с потоками или временным хранилищем является стандартом разработки. Проанализируем правильную цепочку действий:
ТабличныйДокумент.ПотокВПамяти или временного файла на сервере данные конвертируются в ДвоичныеДанные.ДвоичныеДанные помещается во ВременноеХранилище.Мы выяснили, что основной причиной ошибки конструктора ДвоичныеДанные часто является банальная невнимательность при формировании строки пути. Использование стандартных представлений документов с временем (содержащим двоеточия) — главная ловушка для разработчика.
Для создания отказоустойчивых систем мы рекомендуем всегда использовать второй метод — работу через потоки в памяти. Это избавляет код от зависимости от файловой системы и делает его более современным и производительным. Если же специфика задачи требует именно физического сохранения файла, обязательно применяйте функции нормализации строк, чтобы исключить спецсимволы из имен файлов.