Перевод информационной базы 1С с файлового режима работы на клиент-серверный (SQL) — это важный шаг для повышения производительности и отказоустойчивости системы. Однако этот процесс практически всегда сопровождается выявлением скрытых ошибок в старом коде программных модулей. Наиболее уязвимыми оказываются процедуры импорта и экспорта внешних файлов, включая работу с форматом DBF через объект XBase.
В этой статье мы подробно разберем, почему работавший ранее код выгрузки файлов «ломается» при переходе на SQL, проанализируем архитектурные изменения среды исполнения и разработаем надежные решения с использованием современных стандартов платформы 1С:Предприятие 8.3 и Библиотеки Стандартных Подсистем (БСП).
В файловом режиме работы 1С вся логика — и клиентская, и серверная — выполняется на одном и том же физическом компьютере пользователя. Переменные типа «путь к файлу» (например, C:\MyFolder\file.dbf) указывают на локальный диск текущего компьютера. Объект XBase на «сервере» без проблем находил файл по указанному пути, поскольку физический сервер и клиент были объединены в рамках одного процесса.
При переходе на клиент-серверную архитектуру ситуация кардинально меняется:
&НаСервере и передаем туда локальный путь, сервер пытается найти этот файл у себя локально (на сервере приложений). Естественно, сервер ничего не знает о жестком диске пользовательского компьютера и возвращает ошибку доступа или сообщает, что файл не найден.usr1cv8) очень часто не имеет прав на запись и чтение сетевых папок пользователей домена.Единственным правильным, безопасным и кроссплатформенным решением является передача файла между клиентом и сервером в виде потока байтов через специальную область оперативной памяти сервера — Временное Хранилище. Схема взаимодействия выглядит следующим образом:
XBase заполняет этот файл данными на стороне сервера.ДвоичныеДанные.Разберем две критические проблемы, о которых забывают начинающие разработчики:
1. Длина имени файла (стандарт DOS 8.3). Объект XBase исторически чувствителен к длине имени файла и путям к нему. Если использовать стандартную функцию платформы ПолучитьИмяВременногоФайла("dbf"), она сгенерирует очень длинный путь, содержащий GUID (например, C:\Windows\Temp\v8_1A2B_3C.dbf). При записи или индексации такого файла 1С может выдать непредсказуемую ошибку. Поэтому имя временного файла на сервере рекомендуется формировать вручную, обрезая уникальный идентификатор до 8 символов.
2. Использование системного каталога временных файлов. Никогда не используйте жестко прописанные пути вроде "/tmp/" или "C:\Temp". Всегда вызывайте функцию КаталогВременныхФайлов(), которая автоматически вернет корректный путь для текущей операционной системы сервера (будь то Windows или Linux) с учетом прав доступа службы 1С.
Рассмотрим современный асинхронный способ реализации выгрузки. Обратите внимание, что использование синхронных методов работы с файлами (таких как ПолучитьФайл()) в современных версиях платформы 1С 8.3 запрещено по умолчанию.
Создадим на сервере функцию, которая выполнит генерацию файла, запишет его во временное хранилище и удалит «следы» на сервере:
&НаСервере
Функция СформироватьDBFНаСервере()
// Шаг 1. Генерируем уникальное имя файла по стандарту 8.3 для XBase
УникальныйХвост = Лев(СтрЗаменить(Строка(Новый УникальныйИдентификатор()), "-", ""), 8);
ИмяФайлаНаСервере = КаталогВременныхФайлов() + УникальныйХвост + ".dbf";
// Шаг 2. Инициализируем XBase и создаем структуру файла
XBase = Новый XBase;
XBase.Поля.Добавить("p8", "N", 15, 2);
XBase.Кодировка = КодировкаXBase.ANSI;
XBase.СоздатьФайл(ИмяФайлаНаСервере);
// Здесь должен быть ваш код заполнения таблицы DBF
// Пример добавления записи:
XBase.Добавить();
XBase.p8 = 150.50;
XBase.Записать();
// Обязательно закрываем файл, чтобы освободить дескриптор в операционной системе
XBase.ЗакрытьФайл();
// Шаг 3. Читаем файл в двоичные данные и помещаем в хранилище
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ИмяФайлаНаСервере);
АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла);
// Шаг 4. Очищаем серверный диск от временного мусора
Попытка
УдалитьФайлы(ИмяФайлаНаСервере);
Исключение
ЗаписьЖурналаРегистрации("ВыгрузкаDBF.ОшибкаУдаления",
УровеньЖурналаРегистрации.Предупреждение, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
Возврат АдресХранилища;
КонецФункции
Теперь напишем обработчик на клиенте, который вызовет серверную функцию и предложит пользователю сохранить готовый файл на его локальном компьютере с использованием асинхронного метода:
&НаКлиенте
Процедура Выгрузить(Команда)
// Вызываем серверный метод для подготовки файла
АдресХранилища = СформироватьDBFНаСервере();
Если ЗначениеЗаполнено(АдресХранилища) Тогда
// Настраиваем параметры диалога сохранения файла
ПараметрыДиалога = Новый ПараметрыДиалогаПолученияФайлов("Выберите путь для сохранения файла DBF", Истина);
ПараметрыДиалога.Фильтр = "Файлы DBF (*.dbf)|*.dbf";
ПараметрыДиалога.ВыбратьПуть = Истина;
// Передаем файл асинхронно на клиентскую машину
НачатьПолучениеФайлаССервера(АдресХранилища, "v83_data.dbf", ПараметрыДиалога);
КонецЕсли;
КонецПроцедуры
Поскольку в конфигурации «1С:Зарплата и Управление Персоналом» гарантированно встроена Библиотека Стандартных Подсистем (БСП), мы можем существенно упростить клиентский код. Разработчики БСП создали удобные обертки, которые берут на себя всю рутину по обработке асинхронных вызовов в любых типах клиентов (включая веб-клиент в браузере).
Для реализации этого метода серверная функция СформироватьDBFНаСервере() остается без изменений, а клиентская процедура переписывается с использованием модуля ФайловаяСистемаКлиент:
&НаКлиенте
Процедура ВыгрузитьБСП(Команда)
// Шаг 1. Формируем временный файл на сервере и получаем его адрес
АдресХранилища = СформироватьDBFНаСервере();
Если Не ЗначениеЗаполнено(АдресХранилища) Тогда
Возврат;
КонецЕсли;
// Шаг 2. Настраиваем параметры сохранения файла средствами БСП
ПараметрыСохранения = ФайловаяСистемаКлиент.ПараметрыСохраненияФайла();
ПараметрыСохранения.Диалог.Фильтр = "Файлы DBF (*.dbf)|*.dbf";
ПараметрыСохранения.Диалог.Заголовок = "Укажите каталог для сохранения выгрузки";
// Шаг 3. Описываем процедуру обратного вызова после завершения скачивания
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеСохраненияФайла", ЭтотОбъект);
// Шаг 4. БСП самостоятельно откроет диалог и перенесет двоичные данные на диск клиента
ФайловаяСистемаКлиент.СохранитьФайл(ОписаниеОповещения, АдресХранилища, "export_data.dbf", ПараметрыСохранения);
КонецПроцедуры
&НаКлиенте
Процедура ПослеСохраненияФайла(ПолученныеФайлы, ДополнительныеПараметры) Экспорт
Если ПолученныеФайлы <> Неопределено И ПолученныеФайлы.Количество() > 0 Тогда
ПоказатьОповещениеПользователя("Успешно!", , "Файл выгрузки успешно сохранен на ваш диск.");
КонецЕсли;
КонецПроцедуры
Использование механизмов БСП для работы с файлами дает программисту ряд неоспоримых преимуществ:
Таким образом, правильное разделение логики на клиентскую и серверную части, своевременная очистка ресурсов на сервере и использование асинхронных методов позволяют полностью решить проблемы миграции файлового кода в клиент-серверную среду SQL.