Почему возникает ошибка конструктора ДвоичныеДанные «Файл не обнаружен» в 1С 8.3 и как её исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При переходе с платформы 1С 8.2 на версию 1С 8.3 разработчики часто сталкиваются с ситуацией, когда стабильно работавший ранее код начинает вызывать непредвиденные сбои. Одной из таких распространенных проблем является ошибка «Ошибка при вызове конструктора (ДвоичныеДанные): Файл не обнаружен». В этой статье мы подробно разберем, почему один и тот же код ведет себя по-разному в различных версиях платформы, как исправить эту ошибку и как правильно организовать работу с файлами в клиент-серверной архитектуре 1С.

В чем причина ошибки в 1С 8.3?

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


Файл = Новый Файл(Диалог.ПолноеИмяФайла);
Запись.ИмяФайла = Файл.Имя;
// Ошибка возникает на следующей строке:
АдресХранилища = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(Файл.Имя));

В данном примере в конструктор ДвоичныеДанные передается свойство Файл.Имя, которое содержит только непосредственное имя файла с расширением (например, "report.xlsx"), но не содержит информацию о диске и каталогах, где этот файл физически расположен.

Выясним, почему такой код без проблем отрабатывал в 1С 8.2:

  1. Особенности рабочего каталога в 1С 8.2. В старых версиях платформы (особенно в режиме обычного приложения или при использовании толстого клиента) текущий рабочий каталог процесса операционной системы 1cv8.exe часто автоматически переключался на путь последнего открытого интерактивного диалога выбора файлов. Платформа «знала», в какой папке находится пользователь, и успешно находила файл по его краткому имени.
  2. Жесткая изоляция процессов в 1С 8.3. В управляемом приложении 1С 8.3 процессы тонкого и веб-клиента строго изолированы. Рабочим каталогом приложения по умолчанию становится системная папка временных файлов текущего пользователя Windows (в каталоге AppData) или папка самого исполняемого файла платформы. Когда код передает в конструктор только относительное имя файла, платформа ищет его именно в этом изолированном рабочем каталоге. Поскольку выбранного пользователем файла там нет, система незамедлительно генерирует ошибку инициализации объекта ДвоичныеДанные.

Таким образом, для исправления ошибки всегда необходимо передавать в конструктор полный абсолютный путь к файлу на диске.

Решение проблемы: использование полного пути к файлу

Для устранения сбоя достаточно изменить передаваемый параметр в конструкторе. Мы можем использовать свойство ПолноеИмя объекта Файл или напрямую обратиться к свойству ПолноеИмяФайла объекта ДиалогВыбораФайла.

Проанализируем исправленный вариант клиентской процедуры выбора файла:


&НаКлиенте
Процедура ИмяФайлаНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.МножественныйВыбор = Ложь;
    Диалог.Заголовок = "Выберите прикрепляемый файл";
    
    Если Диалог.Выбрать() Тогда
        
        // Создаем объект Файл для получения краткого имени (для записи в реквизит)
        ВыбранныйФайл = Новый Файл(Диалог.ПолноеИмяФайла);
        Запись.ИмяФайла = ВыбранныйФайл.Имя;
        
        // КРИТИЧЕСКИ ВАЖНО: В конструктор ДвоичныеДанные передаем ПОЛНЫЙ путь
        ПолныйПутьКФайлу = ВыбранныйФайл.ПолноеИмя; 
        
        // Помещаем двоичные данные во временное хранилище
        АдресВременногоХранилища = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ПолныйПутьКФайлу));
        
        ЗагрузитьФайлНаСервере(АдресВременногоХранилища);
        
        Элементы.ОткрытьФайл.Видимость = Истина;
        
        Если Не РольДоступнаПолныеПрава() Тогда
            Попытка
                ЭтаФорма.ВладелецФормы.Родитель.Элементы.Список.Обновить();
            Исключение
                // Ошибку обновления списка при закрытии формы можно проигнорировать
            КонецПопытки;
            ЭтаФорма.Закрыть();
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

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

Подводные камни клиент-серверной архитектуры в 1С 8.3

При работе с файловыми объектами крайне важно понимать контекст исполнения кода (клиент или сервер). Попытка инициализировать двоичные данные на сервере по локальному клиентскому пути — одна из самых частых ошибок начинающих разработчиков.

Представим ситуацию: на клиенте мы получили строку пути "C:\MyFolder\document.pdf" и передали её в серверную процедуру. Если на сервере выполнить код Новый ДвоичныеДанные(ПутьПереданныйСКлиента), произойдет следующее:

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

Реализация сохранения и загрузки файлов через Временное Хранилище

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

Часть 1: Интерактивный экспорт данных в файл (Сохранение)

Разберем, как выгрузить структуру данных (например, дерево значений) из базы в файл на компьютере пользователя:


&НаКлиенте
Процедура СохранитьДанныеВФайл(Команда)
    
    ДиалогСохранения = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
    ДиалогСохранения.Фильтр           = "Файлы данных (*.dat)|*.dat";
    ДиалогСохранения.Заголовок        = "Укажите путь для сохранения файла";
    ДиалогСохранения.МножественныйВыбор = Ложь;
    ДиалогСохранения.Расширение       = "dat";
    
    Если ДиалогСохранения.Выбрать() Тогда
        // Получаем двоичные данные файла, сформированного на сервере
        ДвоичныеДанныеФайла = СформироватьФайлНаСервере();
        Если ДвоичныеДанныеФайла <> Неопределено Тогда
            // Записываем полученные двоичные данные по указанному пользователем пути
            ДвоичныеДанныеФайла.Записать(ДиалогСохранения.ПолноеИмяФайла);
            ПоказатьПредупреждение(, "Файл успешно сохранен!");
        КонецЕсли;
    КонецЕсли;    
    
КонецПроцедуры

&НаСервере
Функция СформироватьФайлНаСервере()
    
    // Преобразуем реквизит формы в прикладной объект
    ДеревоОбъект = РеквизитФормыВЗначение("ДеревоОстатков");
    
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("dat");
    Попытка
        // Сохраняем объект во временный файл на сервере
        ЗначениеВФайл(ИмяВременногоФайла, ДеревоОбъект);
        
        // Читаем созданный файл в двоичные данные
        ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ИмяВременногоФайла);
        
        // Удаляем временный файл, так как данные уже находятся в оперативной памяти
        УдалитьФайлы(ИмяВременногоФайла);
        
        Возврат ДвоичныеДанныеФайла;
    Исключение
        ЗаписатьЛогСобытий("Ошибка сохранения: " + ОписаниеОшибки());
        ВызватьИсключение "Не удалось сформировать файл на сервере!";
    КонецПопытки;
    
КонецФункции

Часть 2: Интерактивный импорт данных (Загрузка) с использованием асинхронных вызовов

Начиная с версии платформы 1С 8.3.15, использование синхронных методов работы с файлами в веб-клиенте и некоторых других средах считается устаревшим. Рекомендуется использовать современный асинхронный подход с использованием объектов описания оповещений. Это позволяет загружать файлы без необходимости установки браузерных расширений работы с файлами.

Давайте посмотрим на пример современной асинхронной загрузки файла:


&НаКлиенте
Процедура ЗагрузитьДанныеИзФайла(Команда)
    
    // Создаем оповещение, которое сработает после выбора и загрузки файла
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтаФорма);
    
    ПараметрыДиалога = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    ПараметрыДиалога.Фильтр = "Файлы данных (*.dat)|*.dat";
    ПараметрыДиалога.Заголовок = "Выберите файл для загрузки данных";
    
    // Запуск асинхронного процесса загрузки файла во временное хранилище
    НачатьПомещениеФайлаНаСервер(ОписаниеОповещения, , , , ПараметрыДиалога, УникальныйИдентификатор);
    
КонецПроцедуры

&НаКлиенте
Процедура ПослеПомещенияФайла(РезультатПомещения, ДополнительныеПараметры) Экспорт
    
    Если РезультатПомещения = Неопределено Или Не РезультатПомещения.ИмяФайлаПомещено Тогда
        Возврат; // Пользователь отменил выбор
    КонецЕсли;
    
    // Передаем адрес файла во временном хранилище на сервер для обработки
    ИмпортироватьДанныеНаСервере(РезультатПомещения.Адрес);
    
    ПоказатьПредупреждение(, "Данные успешно импортированы!");
    
КонецПроцедуры

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

Другие частые причины ошибки при создании ДвоичныхДанных

Помимо указания неполного пути к файлу, разработчики могут столкнуться со следующими проблемами при вызове конструктора Новый ДвоичныеДанные:

  1. Блокировка файла операционной системой (Ошибка совместного доступа). Если файл открыт в другой программе (например, таблица Excel открыта пользователем для редактирования) или захвачен антивирусным монитором, операционная система заблокирует чтение файла процессом 1С. В этом случае платформа выбросит исключение доступа. Перед чтением файла убедитесь, что он закрыт во внешних приложениях.
  2. Незакрытые объекты в самом коде 1С. Если вы перед конвертацией в двоичные данные программно записывали информацию в этот файл с помощью объектов ЗаписьТекста, ЗаписьXML или ЗаписьZIPФайла, обязательно вызывайте метод Закрыть() для этих объектов. До тех пор, пока запись не закрыта, файл заблокирован текущим сеансом 1С, и конструктор двоичных данных вернет ошибку совместного доступа.

Использование потоков (Streams) для оптимизации работы с файлами

Если в вашей системе предполагается работа с файлами большого объема (сотни мегабайт или гигабайты), прямое использование конструктора Новый ДвоичныеДанные(Путь) может привести к чрезмерному потреблению оперативной памяти. Конструктор считывает весь файл в память целиком, что может вызвать аварийное завершение рабочего процесса 1С (ошибка нехватки памяти).

Для оптимизации таких задач в платформе 1С 8.3 были реализованы механизмы потоковой работы. Рассмотрим пример открытия потока чтения файла:


&НаКлиенте
Процедура ОбработатьБольшойФайл(ПутьКФайлу)
    
    ФайлИсточник = Новый Файл(ПутьКФайлу);
    Если ФайлИсточник.Существует() Тогда
        // Открываем файл как поток чтения без загрузки всего объема в ОЗУ
        ПотокЧтения = ФайлИсточник.ОткрытьПотокДляЧтения();
        
        // Передаем поток в объект чтения (например, ЧтениеДанных)
        Чтение = Новый ЧтениеДанных(ПотокЧтения);
        
        // Выполняем порционное чтение данных
        Пока Не Чтение.ЧтениеЗавершено() Цикл
            Буфер = Чтение.Прочитать(1024); // Читаем порциями по 1 Кб
            // Обработка буфера данных...
        КонецЦикла;
        
        // Обязательно закрываем поток
        ПотокЧтения.Закрыть();
    КонецЕсли;
    
КонецПроцедуры

Применение потоков позволяет обрабатывать огромные массивы информации с минимальной и прогнозируемой нагрузкой на оперативную память компьютера клиента или сервера.

Подводя итог, помните: при работе с файлами в 1С 8.3 всегда оперируйте полными путями к файлам, четко разграничивайте клиентский и серверный контексты исполнения кода, своевременно закрывайте файловые потоки и отдавайте предпочтение современным асинхронным методам загрузки файлов на сервер.

← На главную