Работа с внешними источниками данных, такими как DBF-файлы, остается актуальной задачей для интеграции с устаревшим ПО или государственными информационными системами. Часто возникает ситуация, когда в базе данных XBase необходимо найти не одну конкретную запись, а целую выборку по определенному условию (фильтру). Стандартный метод Найти() позиционирует указатель только на первой найденной записи, что вводит в заблуждение начинающих разработчиков.
В этой статье мы разберем несколько способов эффективной фильтрации данных в DBF, проанализируем ошибки при создании индексов и выясним, почему старые методы могут перестать работать на новых версиях платформы 1С 8.3.
Проанализируем стандартный алгоритм работы с объектом XBase. Вместо попыток установить «фильтр» в привычном понимании (как в SQL), мы будем использовать комбинацию индексации, точного позиционирования и цикла. Это самый быстрый и надежный способ.
Рассмотрим по шагам, как реализовать этот процесс:
SERIES).Найти(), чтобы встать на первую подходящую запись.Посмотрим на пример кода, реализующий эту логику:
// Подготовка объекта
хВ = Новый XBase;
хВ.ОткрытьФайл(ПутьКФайлу);
хВ.Кодировка = КодировкаXBase.ANSI;
// Создаем индекс для поиска, если он не существует
хВ.Индексы.Добавить("IDX_SERIES", "SERIES", Ложь);
хВ.СоздатьИндексныйФайл(ПутьКФайлуИндекса);
хВ.ТекущийИндекс = хВ.Индексы.IDX_SERIES;
// Поиск первой записи
Если хВ.Найти(ИскомаяСерия, "=") Тогда
Пока Истина Цикл
// Проверяем, не вышли ли мы за пределы нужных данных
Если СокрЛП(хВ.SERIES) <> ИскомаяСерия Тогда
Прервать;
КонецЕсли;
// Извлекаем нужные данные
КодТовара = хВ.CODEGOOD;
Сообщить("Найден код: " + КодТовара);
// Переходим к следующей записи
Если Не хВ.Следующая() Тогда
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
хВ.ЗакрытьФайл();
Выясним причину, по которой некоторые разработчики предпочитают использовать параметры фильтрации непосредственно при создании индекса. Метод Индексы.Добавить позволяет передать выражение фильтра. Это создает так называемый «условный индекс».
Разберем ситуацию на примере кода:
хВ.Индексы.Добавить("IDX_FILTER", "SERIES", , , "SERIES = '" + НужноеЗначение + "'");
хВ.СоздатьИндексныйФайл("C:\temp\temp_idx.cdx");
хВ.ТекущийИндекс = хВ.Индексы.IDX_FILTER;
// Теперь база "видит" только те записи, которые попали в индекс
Если хВ.Первая() Тогда
Пока Истина Цикл
ЗначениеКод = хВ.CODEGOOD;
Если Не хВ.Следующая() Тогда
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Важное предостережение: Хотя этот метод выглядит как «настоящий фильтр», он крайне непроизводителен. При каждом поиске 1С вынуждена полностью перезаписывать файл индекса .cdx на диске. Если в вашем DBF-файле десятки тысяч записей, процедура будет занимать значительное время и создавать лишнюю нагрузку на дисковую подсистему.
Зачастую проще и надежней загрузить данные из DBF в оперативную память 1С и работать с ними стандартными средствами платформы. Рассмотрим, почему это выгодно:
ТаблицеЗначений можно использовать метод НайтиСтроки(), который работает мгновенно..cdx.Проанализируем пример такой загрузки:
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("SERIES");
ТЗ.Колонки.Добавить("CODEGOOD");
хВ = Новый XBase;
хВ.ОткрытьФайл(Путь);
Если хВ.Первая() Тогда
Пока Истина Цикл
НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.SERIES = СокрЛП(хВ.SERIES);
НоваяСтрока.CODEGOOD = хВ.CODEGOOD;
Если Не хВ.Следующая() Тогда Прервать; КонецЕсли;
КонецЦикла;
КонецЕсли;
хВ.ЗакрытьФайл();
// Теперь фильтруем данные штатными средствами 1С
Отбор = Новый Структура("SERIES", ИскомаяСерия);
НайденныеСтроки = ТЗ.НайтиСтроки(Отбор);
Рассмотрим ситуацию, упомянутую в обсуждении: на версии платформы 8.3.13 и выше старые методы работы с XBase могут давать сбои. Выясним основные причины:
1. Права доступа и временные файлы. При использовании метода СоздатьИндексныйФайл() платформа пытается записать файл на диск. Если 1С запущена в клиент-серверном варианте, или если используются строгие политики безопасности Windows, запись в корень диска C:\ или в папку программы будет заблокирована. Проверьте права пользователя, под которым запущен процесс rphost (в случае сервера) или клиентское приложение.
2. Кодировка данных. Это самая частая причина «пустых» результатов поиска. Если DBF создан в DOS-кодировке, а вы открываете его как КодировкаXBase.ANSI, кириллические символы в поле SERIES не совпадут с вашим условием поиска. Всегда проверяйте соответствие OEM и ANSI.
3. Разрядность платформы. 64-битные версии сервера 1С иногда ведут себя иначе с внешними компонентами и драйверами баз данных. Если код работает на тонком клиенте, но не работает на сервере — проблема в доступе к файловой системе или разрядности драйверов Microsoft Jet/ACE (если используется ADO).
4. Длина путей. Старый стандарт XBase чувствителен к именам файлов длиннее 8 символов и путям, содержащим пробелы или спецсимволы. Старайтесь использовать короткие пути для временных индексных файлов, например, через КаталогВременныхФайлов().
В заключение отметим: для разовых задач по поиску нескольких значений лучше всего подходит Метод 1. Если же вам нужно строить сложные отчеты по данным из DBF, настоятельно рекомендуем предварительно загружать их в ТаблицуЗначений или использовать механизм Внешних источников данных платформы 1С:Предприятие.