Как организовать синхронизацию внешнего файлового хранилища в РИБ при работе оффлайн?

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

При разработке распределенных информационных систем (РИБ) на платформе 1С часто возникает задача выноса файлов (картинок, документов) из базы данных в локальный каталог. Это позволяет существенно уменьшить размер самой базы и ускорить выполнение бэкапов. Однако, если система предполагает работу узлов в оффлайне (например, на ноутбуке в поездке), возникает серьезная архитектурная проблема: как синхронизировать эти внешние файлы между центральным и подчиненным узлами без использования облачных сервисов, которые часто создают дубли и конфликты.

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

Проблема использования стандартных облачных решений

Многие разработчики в первую очередь рассматривают использование облачных сервисов (Яндекс.Диск, Google Drive, OneDrive) для синхронизации папок. Но в контексте РИБ этот подход имеет критические недостатки:

  1. Конфликты и дублирование: Если один и тот же файл был изменен или перемещен на обоих узлах в оффлайне, облачный сервис при подключении создаст копии файла (например, "документ (1).pdf"), которые база 1С не увидит, так как она хранит путь только к оригинальному имени.
  2. Проблема удаления: Удаление файла в базе 1С на одном узле должно приводить к физическому удалению файла на всех узлах. Облачные синхронизаторы при определенных настройках могут "восстановить" удаленный файл, посчитав его отсутствие ошибкой синхронизации.
  3. Безопасность: Хранение корпоративных данных на публичных серверах не всегда допустимо.

Именно поэтому для надежной работы оффлайн-узлов необходимо встраивать логику передачи файлов непосредственно в механизм обмена 1С или использовать специализированные P2P-инструменты.

Решение №1: Метод «Транзитного реквизита» в сообщениях РИБ

Проанализируем наиболее изящный метод, предложенный в обсуждении. Суть его заключается в том, что файлы перемещаются между узлами внутри стандартного XML-сообщения обмена РИБ, но не задерживаются в базе данных на постоянной основе. Рассмотрим алгоритм реализации по шагам.

1. Создание структуры хранения данных

В справочнике, который отвечает за хранение информации о файлах (например, Справочник.ПрисоединенныеФайлы), создадим служебный реквизит ДанныеДляПередачи с типом ХранилищеЗначения. Этот реквизит должен быть включен в состав плана обмена.

2. Обработка перед отправкой данных

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


// Пример помещения файла в транзитный реквизит
Если ЭтоНовый() Или ФайлБылИзменен Тогда
    ПолныйПуть = ПолучитьПолныйПутьКФайлу(ЭтотОбъект.ПутьНаДиске);
    ДвоичныеДанные = Новый ДвоичныеДанные(ПолныйПуть);
    ЭтотОбъект.ДанныеДляПередачи = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));
КонецЕсли;

3. Обработка при получении данных на другом узле

При загрузке сообщения РИБ на принимающей стороне сработает событие записи объекта. В этот момент нам нужно извлечь данные из реквизита ДанныеДляПередачи, сохранить их в локальное файловое хранилище узла и — что крайне важно — очистить реквизит ДанныеДляПередачи, чтобы он не раздувал базу данных.


// Пример извлечения файла на узле-приемнике
Процедура ПриЗаписи(Отказ)
    Если ЭтотОбъект.ДанныеДляПередачи <> Неопределено Тогда
        Данные = ЭтотОбъект.ДанныеДляПередачи.Получить();
        Если ТипЗнч(Данные) = Тип("ДвоичныеДанные") Тогда
            ПутьСохранения = ОпределитьЛокальныйПуть(ЭтотОбъект);
            Данные.Записать(ПутьСохранения);
            
            // Очищаем, чтобы не занимать место в БД
            ЭтотОбъект.ДанныеДляПередачи = Неопределено;
            
            // Важно: отключаем обмен для этой записи, чтобы не зациклить
            ЭтотОбъект.ОбменДанными.Загрузка = Истина;
            ЭтотОбъект.Записать();
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Этот метод гарантирует, что файл "приедет" на другой узел строго вместе с метаданными (ссылкой, наименованием, автором) в одном пакете обмена. Сразу после "приезда" файл выгружается на диск, а база остается компактной.

Решение №2: Использование специализированного P2P ПО (Syncthing)

Если объем файлов исчисляется гигабайтами, передача их через XML-сообщения РИБ может привести к ошибкам нехватки памяти (Out of Memory) или гигантским файлам обмена. В этом случае выясним, как настроить прямую синхронизацию папок минуя облако.

Рассмотрим инструмент Syncthing. Это бесплатное решение с открытым исходным кодом, которое идеально подходит для связки "Компьютер - Ноутбук":

Для реализации этого подхода в 1С достаточно хранить в базе относительные пути к файлам. Например, корень хранилища на ПК — C:\Work\Files\, на ноутбуке — D:\Storage\Files\. В базе храним только my_doc.pdf. Перед открытием файла программно подставляем путь к локальному корню, используя константу или параметр сеанса.

Оптимизация работы с большими сообщениями РИБ

Если мы выбрали Решение №1 (передача через базу), проанализируем ситуацию с объемом данных. Стандартная запись ХранилищеЗначения в XML преобразует двоичные данные в формат Base64, что увеличивает размер сообщения на 33%. Для оптимизации рекомендуем:

  1. Потоковая запись: Использовать объекты ЗаписьXML и ЧтениеXML напрямую для обработки данных порциями, если вы пишете свой механизм обмена.
  2. Служебный регистр: Вместо реквизита справочника лучше использовать РегистрСведений.ОчередьПередачиФайлов. Это позволит более гибко управлять очередью: например, не отправлять файлы тяжелее 10 Мб, если связь нестабильна, или отправлять их отдельным пакетом обмена.

Обработка удаления файлов

Это самый тонкий момент архитектуры. Если мы просто удалим файл на диске, другой узел может этого "не заметить". Проанализируем правильный алгоритм удаления:

  1. В 1С объект файла помечается на удаление или устанавливается флаг ФайлУдален = Истина.
  2. Это изменение синхронизируется через РИБ как обычное текстовое поле.
  3. На каждом узле работает регламентное задание (или код в ПриЗаписи), которое проверяет этот флаг и физически удаляет файл с локального диска.

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

Резюме

Выбор решения зависит от масштаба системы. Для небольшого количества документов идеально подходит метод транзитного реквизита (Решение №1). Он прост в реализации, не требует стороннего ПО и гарантирует целостность данных. Если же база предполагает работу с тяжелым контентом (фото высокого разрешения, видео), стоит посмотреть в сторону P2P-синхронизации (Решение №2), оставив за 1С только управление логикой прав и путей.

← На главную