Как во внешней обработке 1С сохранять данные внутри самого файла для переноса между базами

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

При работе с внешними обработками (файлы .epf или .erf) часто возникает задача сохранения результатов работы или настроек таким образом, чтобы они «путешествовали» вместе с файлом. Стандартные механизмы 1С, такие как ХранилищеНастроек, привязаны к конкретной информационной базе. Если вы скопируете обработку на флешку и откроете её в другой базе, все сохраненные данные будут утеряны. В этой статье мы разберем продвинутые методы, которые позволяют записывать информацию прямо в тело файла обработки.

Метод 1: Использование двоичных потоков и маркера в конце файла

Самый эффективный способ сохранить данные «внутри себя» — это дописать их в конец бинарного файла обработки. Чтобы при последующем чтении программа знала, где заканчивается программный код 1С и начинаются ваши данные, мы будем использовать специальный идентификатор — Маркер.

Разберем алгоритм реализации этого метода. Сначала нам нужно подготовить маркер и определить местоположение файла. Проанализируем пример кода для записи произвольного файла (например, картинки или архива) в тело обработки:


&НаКлиенте
Процедура ЗаписатьДанныеВСебя(Команда)
    // 1. Подготавливаем маркер (уникальное число или строка)
    Маркер = Новый БуферДвоичныхДанных(4);
    Маркер.ЗаписатьЦелое32(0, 777777777); // Наш уникальный код

    // 2. Выбираем файл, который хотим внедрить
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Если Не Диалог.Выбрать() Тогда Возврат; КонецЕсли;

    // 3. Читаем внедряемые данные
    ЧтениеДП = Новый ЧтениеДанных(Диалог.ВыбранныеФайлы[0]);
    РезультатЧтения = ЧтениеДП.Прочитать();
    ДанныеДляЗаписи = РезультатЧтения.ПолучитьБуферДвоичныхДанных();
    ЧтениеДП.Закрыть();

    // 4. Определяем размер оригинальной обработки до маркера
    ПутьКФайлу = ИспользуемоеИмяФайла; // Путь к текущей EPF
    ЧтениеОбработки = Новый ЧтениеДанных(ПутьКФайлу);
    ПозицияМаркера = ЧтениеОбработки.ПропуститьДо(Маркер);
    
    Если ПозицияМаркера = -1 Тогда
        // Если маркера нет, пишем в конец файла
        РазмерОригинала = ЧтениеОбработки.ИсходныйПоток().Размер;
    Иначе
        // Если маркер найден, перезаписываем данные после него
        РазмерОригинала = ПозицияМаркера;
    КонецЕсли;
    ЧтениеОбработки.Закрыть();

    // 5. Записываем данные в файл
    ФайловыйПоток = Новый ФайловыйПоток(ПутьКФайлу, РежимОткрытияФайла.Открыть, ДоступКФайлу.Запись);
    ФайловыйПоток.Перейти(РазмерОригинала, ПозицияВПотоке.Начало);
    ФайловыйПоток.Записать(Маркер, 0, 4);
    ФайловыйПоток.Записать(ДанныеДляЗаписи, 0, ДанныеДляЗаписи.Размер);
    ФайловыйПоток.Закрыть();
КонецПроцедуры

Теперь рассмотрим, как прочитать эти данные обратно при открытии обработки в другой базе. Нам нужно снова найти позицию нашего маркера в потоке ИспользуемоеИмяФайла и считать всё, что следует за ним.


&НаКлиенте
Процедура ПрочитатьВнедренныеДанные()
    Маркер = Новый БуферДвоичныхДанных(4);
    Маркер.ЗаписатьЦелое32(0, 777777777);

    Чтение = Новый ЧтениеДанных(ИспользуемоеИмяФайла);
    Если Чтение.ПропуститьДо(Маркер) <> -1 Тогда
        // Читаем всё, что идет после маркера
        ДвоичныеДанныеРезультат = Чтение.Прочитать().ПолучитьДвоичныеДанные();
        // Далее работаем с ДвоичныеДанные (сохраняем во временное хранилище или файл)
    Иначе
        Сообщить("Данные внутри файла не обнаружены.");
    КонецЕсли;
    Чтение.Закрыть();
КонецПроцедуры

Метод 2: Хранение сложных структур (Таблицы значений, Списки)

Если вам нужно сохранить не просто файл, а таблицу или структуру 1С, её необходимо предварительно сериализовать. Проанализируем, как превратить ТаблицаЗначений в формат, пригодный для записи в двоичный поток.

Выясним причину использования ХранилищеЗначения: этот объект позволяет упаковать любой сериализуемый объект 1С в бинарный вид. Для надежности мы можем использовать Base64 или прямой БуферДвоичныхДанных.

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


// На сервере преобразуем ТЗ в двоичные данные
Хранилище = Новый ХранилищеЗначения(МояТаблицаЗначений);
ДвоичныеДанныеТЗ = Base64Значение(XMLСтрока(Хранилище));
// Далее записываем ДвоичныеДанныеТЗ в файл методом, описанным выше

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


// Получив ДвоичныеДанные из файла, превращаем их обратно в ТЗ
СтрокаBase64 = Base64Строка(ДвоичныеДанныеИзФайла);
Хранилище = XMLЗначение(Тип("ХранилищеЗначения"), СтрокаBase64);
МояТаблицаЗначений = Хранилище.Получить();

Метод 3: Использование макетов обработки

Рассмотрим еще один интересный вариант. В составе обработки можно создать макет типа Текстовый документ или Двоичные данные. Программно изменить содержимое макета в «самом себе» сложнее, чем просто дописать данные в конец файла, так как .epf имеет сложную внутреннюю структуру (по сути, это ZIP-архив с особым заголовком).

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

  1. Создаем временную копию текущего файла .epf.
  2. Открываем её как поток.
  3. Ищем уникальную строку-заполнитель, заранее оставленную в макете.
  4. Заменяем её на новые данные.
  5. Предлагаем пользователю сохранить обновленный файл.

Важные технические нюансы и ограничения

Проанализируем ситуацию с безопасностью и стабильностью. Работа с файлами «самого себя» имеет ряд особенностей:

Синхронные и асинхронные вызовы: В современных версиях платформы 1С (начиная с 8.3.15+) использование синхронных методов работы с файлами на клиенте запрещено. Это значит, что вместо ФайловыйПоток и ЧтениеДанных в их обычном виде, вам придется использовать асинхронные версии с обратными вызовами (например, через НачатьЗапись...). Однако в режиме «0» (совместимость) или при использовании специальных параметров запуска старый код может работать.

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

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

Альтернатива (Облако): Если наличие интернета гарантировано, разберем более современный подход. Вместо флешки можно использовать HTTP-сервис или простой Telegram-бот. Обработка при закрытии отправляет JSON-пакет с данными на ваш сервер/бот, а при открытии в другой базе — скачивает его по уникальному идентификатору (например, по серийному номеру процессора или ключу пользователя). Это избавляет от необходимости манипулировать бинарным кодом файла.

Выясним, какой метод лучше. Если вам нужна полная автономность и работа «с флешки», Метод 1 (Маркер) является самым надежным и простым в реализации для программиста 1С. Он позволяет превратить внешнюю обработку в полноценный контейнер, несущий в себе и логику, и данные.

← На главную