При переходе с файловой информационной базы на клиент-серверный вариант разработчики нередко сталкиваются с ситуацией: код загрузки данных из внешнего файла DBF, успешно работавший ранее, внезапно перестает функционировать. При выполнении кода на стороне сервера метод навигации по записям вызывает исключение: «Перед выполнением операции нужно открыть базу». Разберем по шагам, почему возникает эта ошибка и как правильно организовать чтение DBF-файлов в клиент-серверной архитектуре 1С:Предприятия.
Рассмотрим типовой фрагмент кода, приводящий к ошибке:
хб = Новый XBase();
хб.ОткрытьФайл("E:\temp\1.dbf");
хб.Первая();
В файловой версии данный код исполняется в контексте клиентского приложения, поэтому файл без проблем открывается. Однако на сервере 1С вызов метода Первая() приводит к сбою. Выясним причину такого поведения платформы и детально изучим способы устранения проблемы.
Главная коварность объекта XBase заключается в том, что метод ОткрытьФайл() при неудачной попытке доступа к файлу не генерирует исключение платформы. Конструкция Попытка ... Исключение не перехватывает сбой, метод просто завершает свою работу, оставляя объект в закрытом состоянии. Ошибка возникает уже на следующем шаге, когда мы вызываем метод Первая() или Следующая() у фактически неоткрытой таблицы.
Чтобы избежать неожиданных падений и сразу понимать причину проблемы, проанализируем состояние объекта с помощью свойства Открыта(), а также предварительно проверим физическое наличие файла через объект Файл:
ПутьКФайлу = "E:\temp\1.dbf";
ФайлНаДиске = Новый Файл(ПутьКФайлу);
Если Не ФайлНаДиске.Существует() Тогда
ВызватьИсключение "Файл не найден серверным процессом: " + ПутьКФайлу;
КонецЕсли;
хб = Новый XBase();
хб.ОткрытьФайл(ПутьКФайлу);
Если Не хб.Открыта() Тогда
ВызватьИсключение "Не удалось открыть DBF-файл. Проверьте блокировки и формат файла.";
КонецЕсли;
хб.Первая();
Даже если сервер 1С установлен на том же компьютере, где запущен клиент, исполнение кода на сервере происходит в контексте системной службы (по умолчанию это пользователь операционной системы usr1cv8). Пользователь, под которым выполнен вход в Windows, может обладать полными правами администратора на папку E:\temp\, но служба сервера 1С этих прав не имеет.
Разберем действия для исправления прав доступа:
E:\temp\).usr1cv8 или NETWORK SERVICE в зависимости от конфигурации сервера).Служба сервера 1С функционирует в изолированной нулевой сессии Windows (Session 0). Это накладывает важные ограничения на работу с файловой системой:
E: подключена как сетевой ресурс под учетной записью администратора или пользователя, сервер 1С ее не увидит, так как подключенные диски существуют исключительно в рамках конкретной пользовательской сессии.\\server\share\temp\1.dbf вместо букв дисков. При этом у учетной записи сервера 1С должны быть предоставлены права как на сетевой общий доступ (Share Permissions), так и на уровне файловой системы (NTFS Permissions).По умолчанию метод ОткрытьФайл(ИмяФайла, ИмяИндекса, ТолькоЧтение) принимает третий параметр как Ложь. Это означает, что 1С пытается открыть таблицу на чтение и запись с наложением файловых блокировок. Если файл в этот момент открыт другой программой (например, табличным редактором или внешней учетной системой), метод не сможет открыть базу.
Если требуется только прочитать данные, всегда явно указываем режим только для чтения:
хб = Новый XBase();
// Третий параметр Истина открывает файл в режиме ТолькоЧтение
хб.ОткрытьФайл("E:\temp\1.dbf", , Истина);
Если хб.Открыта() Тогда
хб.Первая();
// Обработка данных
хб.ЗакрытьФайл();
КонецЕсли;
Также не забываем обязательно вызывать метод ЗакрытьФайл() после завершения работы. Если открытый файл не закрыть в коде, серверный процесс rphost будет удерживать файловый дескриптор, что заблокирует последующие обращения к этому файлу вплоть до перезапуска процесса или службы.
В управляемом приложении оптимальной практикой является передача файла с клиентского компьютера во временное хранилище с последующим сохранением во временную папку сервера. Такой подход полностью исключает проблемы с правами на пользовательские каталоги и сетевые диски.
Посмотрим на пример правильной архитектуры передачи и обработки файла:
&НаСервере
Процедура ПрочитатьФайлИзХранилищаНаСервере(АдресВХранилище)
// Получаем двоичные данные из временного хранилища
Двоичные = ПолучитьИзВременногоХранилища(АдресВХранилище);
УдалитьИзВременногоХранилища(АдресВХранилище);
// Создаем гарантированно доступный временный файл на стороне сервера
ВременныйПуть = ПолучитьИмяВременногоФайла("dbf");
Двоичные.Записать(ВременныйПуть);
ТаблицаDBF = Новый XBase();
ТаблицаDBF.ОткрытьФайл(ВременныйПуть, , Истина);
Если Не ТаблицаDBF.Открыта() Тогда
УдалитьФайлы(ВременныйПуть);
ВызватьИсключение "Не удалось прочитать переданный DBF-файл на сервере.";
КонецЕсли;
Попытка
ТаблицаDBF.Первая();
Пока Не ТаблицаDBF.ВКонце() Цикл
// Считываем поля записи: ТаблицаDBF.ИмяПоля
ТаблицаDBF.Следующая();
КонецЦикла;
Исключение
ТаблицаDBF.ЗакрытьФайл();
УдалитьФайлы(ВременныйПуть);
ВызватьИсключение;
КонецПопытки;
ТаблицаDBF.ЗакрытьФайл();
УдалитьФайлы(ВременныйПуть);
КонецПроцедуры
Если права настроены, путь проверен, но файл по-прежнему не открывается объектом XBase, проанализируем следующие системные настройки:
XBase поддерживает стандарты dBase III, dBase IV и ранние форматы FoxPro. Файлы Visual FoxPro со специфическими типами полей (DateTime, Integer, поля автоинкремента, внешние memo-файлы .fpt) объект открыть не сможет.Применение проверки Открыта(), открытие в режиме ТолькоЧтение и передача файла через временные файлы сервера позволяют надежно изолировать процесс обработки DBF от ограничений клиент-серверной среды.