Резервное копирование — это критически важная задача для любой информационной системы. Особенно остро этот вопрос стоит для файловых баз данных 1С, которые более чувствительны к сбоям электропитания или ошибкам файловой системы, чем серверные решения. В рамках данной статьи мы подробно разберем, как реализовать механизм автоматического или полуавтоматического резервирования в самописной конфигурации, проанализируем различные подходы и выберем наиболее надежные инструменты.
Прежде чем переходить к программному коду, разберем важный теоретический аспект. Часто начинающие разработчики стремятся автоматизировать именно выгрузку в формат .dt. Однако стоит помнить, что файл .dt — это логическое представление данных, созданное для перехода между лицензиями или версиями СУБД. Для регулярного бэкапа файловой базы гораздо надежнее использовать прямое копирование файла 1Cv8.1CD.
Рассмотрим основные риски формата .dt:
.dt может пройти успешно, а вот восстановить из него базу (загрузить обратно) не удастся..dt требует исключительно монопольного режима работы с конфигуратором, что технически сложнее реализовать "на лету" при закрытии сеанса пользователем..dt нагружает процессор и занимает значительное время при больших объемах данных.Поэтому в наших примерах мы сделаем упор на копирование основного файла базы данных и его архивацию.
Рассмотрим ситуацию, когда необходимо предложить пользователю сделать копию именно в момент выхода из системы. Для этого нам понадобится модуль управляемого приложения и процедура ПередЗавершениемРаботыСистемы. Проанализируем алгоритм: мы должны спросить пользователя о необходимости бэкапа и, если он согласен, запустить процесс.
Важный нюанс: Программа 1С не может скопировать свой собственный файл базы 1Cv8.1CD, пока он открыт и заблокирован самой же программой. Поэтому прямое использование функции КопироватьФайл() внутри 1С для текущей базы выдаст ошибку доступа. Мы обойдем это ограничение с помощью внешнего командного файла (bat-скрипта).
Разберем пример кода в модуле управляемого приложения:
Процедура ПередЗавершениемРаботыСистемы(Отказ)
// Проверим, не делали ли мы уже бэкап сегодня (используем константу или параметр сеанса)
ДатаПоследнейКопии = Константы.ДатаПоследнегоРезервногоКопирования.Получить();
Если НачалоДня(ДатаПоследнейКопии) = НачалоДня(ТекущаяДата()) Тогда
Возврат; // Сегодня копия уже создавалась
КонецЕсли;
ТекстВопроса = "Сформировать резервную копию базы данных перед выходом?";
Ответ = Вопрос(ТекстВопроса, РежимДиалогаВопрос.ДаНет, 15, КодВозвратаДиалога.Да, "Резервное копирование");
Если Ответ = КодВозвратаДиалога.Да Тогда
ПутьКБазе = СтрокаСоединенияИнформационнойБазы();
// Извлекаем путь к папке из строки соединения (File="C:\MyBase";)
ЧистыйПуть = СтрЗаменить(ПутьКБазе, "File=""", "");
ЧистыйПуть = СтрЗаменить(ЧистыйПуть, """;", "");
ЗапуститьСкриптБэкапа(ЧистыйПуть);
КонецЕсли;
КонецПроцедуры
Чтобы успешно скопировать заблокированный файл, мы создадим процедуру, которая генерирует временный .bat файл. Этот файл подождет несколько секунд (пока 1С полностью закроется), а затем скопирует базу. Проанализируем пример такой процедуры:
Процедура ЗапуститьСкриптБэкапа(ПутьКБазе)
ИмяФайлаСкрипта = "C:\Backups\start_backup.bat";
ТекстСкрипта = "timeout /t 5 /nobreak" + Символы.ПС; // Ждем 5 секунд закрытия 1С
ТекстСкрипта = ТекстСкрипта + "xcopy """ + ПутьКБазе + "1Cv8.1CD"" ""C:\Backups\Backup_" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd") + ".1CD*"" /y" + Символы.ПС;
// Записываем скрипт в файл
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.УстановитьТекст(ТекстСкрипта);
ТекстовыйДокумент.Записать(ИмяФайлаСкрипта, КодировкаТекста.OEM);
// Запускаем скрипт без ожидания завершения
ЗапуститьПриложение(ИмяФайлаСкрипта);
// Обновляем дату последней копии в 1С
Константы.ДатаПоследнегоРезервногоКопирования.Установить(ТекущаяДата());
КонецПроцедуры
Если мы не хотим беспокоить пользователя при закрытии, рассмотрим вариант с проверкой при начале работы. Выясним причину, по которой это удобнее: пользователь полон сил в начале дня и готов подождать лишние 30 секунд, пока создается архив. Логика размещается в процедуре ПриНачалеРаботыСистемы.
Для контроля периодичности нам понадобится Регистр сведений (например, "ИсторияБэкапов") или Константа. Рассмотрим вариант с использованием объекта ЗаписьZipФайла, который позволяет сжать базу объемом 3 Мб до нескольких сотен килобайт средствами самой 1С.
Пример кода для создания ZIP-архива при запуске:
Процедура ПриНачалеРаботыСистемы()
ДатаПоследнейКопии = Константы.ДатаПоследнегоРезервногоКопирования.Получить();
Если НачалоДня(ДатаПоследнейКопии) < НачалоДня(ТекущаяДата()) Тогда
Попытка
// Определяем пути
ПутьКФайлуБазы = "C:\MyBase\1Cv8.1CD";
ПутьАрхива = "D:\Backups\Archive_" + Формат(ТекущаяДата(), "ДФ=yyyy_MM_dd") + ".zip";
// Создаем архив
Архив = Новый ЗаписьZipФайла(ПутьАрхива, , , МетодСжатияZip.Сжатие, УровеньСжатияZip.Максимальный);
Архив.Добавить(ПутьКФайлуБазы, РежимСохраненияПутейZip.НеСохранятьПути);
Архив.Записать();
// Фиксируем успех
Константы.ДатаПоследнегоРезервногоКопирования.Установить(ТекущаяДата());
Сообщить("Автоматическое резервное копирование успешно завершено.");
Исключение
// Если файл занят другим пользователем, Zip вызовет исключение
ЗаписьЖурналаРегистрации("Бэкап", УровеньЖурналаРегистрации.Ошибка, , , "Ошибка создания копии: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Если конфигурация становится сложной или пользователей становится больше одного, рассмотрим использование внешнего софта, такого как Effector Saver. Это профессиональное решение, которое умеет:
Это зачастую надежнее, чем самописный код, так как внешние утилиты используют технологию VSS (Volume Shadow Copy), позволяющую копировать файлы "на лету" без остановки работы программы.
Проанализируем ситуацию: вы настроили копирование, база сохраняется в соседнюю папку на диске C:. Выясним, почему это опасно. Если жесткий диск выйдет из строя, вы потеряете и рабочую базу, и все копии.
Посмотрим на "Правило 3-2-1" для резервного копирования:
Также важно предусмотреть очистку дискового пространства. Если ваша база весит 3 Мб, это не критично, но со временем архивов станет слишком много. Проанализируем код для удаления файлов старше 30 дней:
МассивФайлов = НайтиФайлы("D:\Backups\", "*.zip");
Для Каждого Файл Из МассивФайлов Цикл
Если (ТекущаяДата() - Файл.ПолучитьВремяИзменения()) > (30 * 24 * 60 * 60) Тогда
Попытка
УдалитьФайлы(Файл.ПолноеИмя);
Исключение
// Файл может быть занят другим процессом
КонецПопытки;
КонецЕсли;
КонецЦикла;
Таким образом, мы разобрали комплексный подход к созданию системы резервного копирования. Для небольших самописных конфигураций оптимальным будет сочетание проверки даты последнего бэкапа при запуске и использование объекта ЗаписьZipФайла с последующим копированием архива в "облачную" папку.