При работе с внешними обработками (файлы .epf или .erf) часто возникает задача сохранения результатов работы или настроек таким образом, чтобы они «путешествовали» вместе с файлом. Стандартные механизмы 1С, такие как ХранилищеНастроек, привязаны к конкретной информационной базе. Если вы скопируете обработку на флешку и откроете её в другой базе, все сохраненные данные будут утеряны. В этой статье мы разберем продвинутые методы, которые позволяют записывать информацию прямо в тело файла обработки.
Самый эффективный способ сохранить данные «внутри себя» — это дописать их в конец бинарного файла обработки. Чтобы при последующем чтении программа знала, где заканчивается программный код 1С и начинаются ваши данные, мы будем использовать специальный идентификатор — Маркер.
Разберем алгоритм реализации этого метода. Сначала нам нужно подготовить маркер и определить местоположение файла. Проанализируем пример кода для записи произвольного файла (например, картинки или архива) в тело обработки:
&НаКлиенте
Процедура ЗаписатьДанныеВСебя(Команда)
// 1. Подготавливаем маркер (уникальное число или строка)
Маркер = Новый БуферДвоичныхДанных(4);
Маркер.ЗаписатьЦелое32(0, 777777777); // Наш уникальный код
// 2. Выбираем файл, который хотим внедрить
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Если Не Диалог.Выбрать() Тогда Возврат; КонецЕсли;
// 3. Читаем внедряемые данные
ЧтениеДП = Новый ЧтениеДанных(Диалог.ВыбранныеФайлы[0]);
РезультатЧтения = ЧтениеДП.Прочитать();
ДанныеДляЗаписи = РезультатЧтения.ПолучитьБуферДвоичныхДанных();
ЧтениеДП.Закрыть();
// 4. Определяем размер оригинальной обработки до маркера
ПутьКФайлу = ИспользуемоеИмяФайла; // Путь к текущей EPF
ЧтениеОбработки = Новый ЧтениеДанных(ПутьКФайлу);
ПозицияМаркера = ЧтениеОбработки.ПропуститьДо(Маркер);
Если ПозицияМаркера = -1 Тогда
// Если маркера нет, пишем в конец файла
РазмерОригинала = ЧтениеОбработки.ИсходныйПоток().Размер;
Иначе
// Если маркер найден, перезаписываем данные после него
РазмерОригинала = ПозицияМаркера;
КонецЕсли;
ЧтениеОбработки.Закрыть();
// 5. Записываем данные в файл
ФайловыйПоток = Новый ФайловыйПоток(ПутьКФайлу, РежимОткрытияФайла.Открыть, ДоступКФайлу.Запись);
ФайловыйПоток.Перейти(РазмерОригинала, ПозицияВПотоке.Начало);
ФайловыйПоток.Записать(Маркер, 0, 4);
ФайловыйПоток.Записать(ДанныеДляЗаписи, 0, ДанныеДляЗаписи.Размер);
ФайловыйПоток.Закрыть();
КонецПроцедуры
Теперь рассмотрим, как прочитать эти данные обратно при открытии обработки в другой базе. Нам нужно снова найти позицию нашего маркера в потоке ИспользуемоеИмяФайла и считать всё, что следует за ним.
&НаКлиенте
Процедура ПрочитатьВнедренныеДанные()
Маркер = Новый БуферДвоичныхДанных(4);
Маркер.ЗаписатьЦелое32(0, 777777777);
Чтение = Новый ЧтениеДанных(ИспользуемоеИмяФайла);
Если Чтение.ПропуститьДо(Маркер) <> -1 Тогда
// Читаем всё, что идет после маркера
ДвоичныеДанныеРезультат = Чтение.Прочитать().ПолучитьДвоичныеДанные();
// Далее работаем с ДвоичныеДанные (сохраняем во временное хранилище или файл)
Иначе
Сообщить("Данные внутри файла не обнаружены.");
КонецЕсли;
Чтение.Закрыть();
КонецПроцедуры
Если вам нужно сохранить не просто файл, а таблицу или структуру 1С, её необходимо предварительно сериализовать. Проанализируем, как превратить ТаблицаЗначений в формат, пригодный для записи в двоичный поток.
Выясним причину использования ХранилищеЗначения: этот объект позволяет упаковать любой сериализуемый объект 1С в бинарный вид. Для надежности мы можем использовать Base64 или прямой БуферДвоичныхДанных.
Пример упаковки таблицы значений:
// На сервере преобразуем ТЗ в двоичные данные
Хранилище = Новый ХранилищеЗначения(МояТаблицаЗначений);
ДвоичныеДанныеТЗ = Base64Значение(XMLСтрока(Хранилище));
// Далее записываем ДвоичныеДанныеТЗ в файл методом, описанным выше
Пример распаковки таблицы значений:
// Получив ДвоичныеДанные из файла, превращаем их обратно в ТЗ
СтрокаBase64 = Base64Строка(ДвоичныеДанныеИзФайла);
Хранилище = XMLЗначение(Тип("ХранилищеЗначения"), СтрокаBase64);
МояТаблицаЗначений = Хранилище.Получить();
Рассмотрим еще один интересный вариант. В составе обработки можно создать макет типа Текстовый документ или Двоичные данные. Программно изменить содержимое макета в «самом себе» сложнее, чем просто дописать данные в конец файла, так как .epf имеет сложную внутреннюю структуру (по сути, это ZIP-архив с особым заголовком).
Однако мы можем использовать макет как «хранилище по умолчанию». Если данные в конце файла не найдены, обработка берет их из макета. Процесс записи в этом случае может выглядеть как создание копии файла обработки с измененным блоком данных макета. Рассмотрим по шагам:
.epf.Проанализируем ситуацию с безопасностью и стабильностью. Работа с файлами «самого себя» имеет ряд особенностей:
Синхронные и асинхронные вызовы: В современных версиях платформы 1С (начиная с 8.3.15+) использование синхронных методов работы с файлами на клиенте запрещено. Это значит, что вместо ФайловыйПоток и ЧтениеДанных в их обычном виде, вам придется использовать асинхронные версии с обратными вызовами (например, через НачатьЗапись...). Однако в режиме «0» (совместимость) или при использовании специальных параметров запуска старый код может работать.
Блокировка файла: Когда обработка открыта в 1С, файл .epf может быть заблокирован операционной системой для записи. Рассмотрим решение: перед записью данных рекомендуется закрыть все потоки чтения и, если блокировка сохраняется, производить запись в копию файла, которую затем пользователь сможет переименовать или заменить.
Целостность структуры: Дозапись данных в конец файла (после всей структуры 1С) обычно не портит обработку, и она продолжает открываться в Конфигураторе. Но будьте осторожны: если вы случайно затрете служебные заголовки 1С внутри файла, обработка перестанет запускаться с ошибкой «Неверный формат хранилища данных».
Альтернатива (Облако): Если наличие интернета гарантировано, разберем более современный подход. Вместо флешки можно использовать HTTP-сервис или простой Telegram-бот. Обработка при закрытии отправляет JSON-пакет с данными на ваш сервер/бот, а при открытии в другой базе — скачивает его по уникальному идентификатору (например, по серийному номеру процессора или ключу пользователя). Это избавляет от необходимости манипулировать бинарным кодом файла.
Выясним, какой метод лучше. Если вам нужна полная автономность и работа «с флешки», Метод 1 (Маркер) является самым надежным и простым в реализации для программиста 1С. Он позволяет превратить внешнюю обработку в полноценный контейнер, несущий в себе и логику, и данные.