Часто начинающие разработчики 1С при работе с внешними базами данных формата DBF сталкиваются с трудностями при обновлении существующих данных. Распространенной ошибкой является попытка удалить нужную строку, запустить сжатие таблицы методом Сжать(), а затем добавить новую строку с измененными значениями. Такой подход не только избыточен, но и существенно снижает производительность системы, блокирует файл и может нарушить структуру индексных файлов или физический порядок записей в DBF-таблице.
В этой статье мы подробно разберем, как правильно и быстро изменить значение поля в существующей строке DBF с помощью стандартного объекта XBase, работающего по принципу курсора.
Прежде чем переходить к написанию кода модификации полей, давайте вспомним, как в принципе устроен механизм работы с DBF через объект XBase. Данный объект работает по принципу курсора — последовательного указателя на текущую активную запись. Чтобы изменить данные, нам необходимо выполнить следующие шаги:
Рассмотрим каждый из этих шагов подробнее.
Для того чтобы иметь возможность изменять данные, файл обязательно должен быть открыт с возможностью модификации. Посмотрим на синтаксис метода ОткрытьФайл(). Третий параметр этого метода отвечает за режим "Только чтение". Нам необходимо передать туда значение Ложь (которое также является значением по умолчанию, если параметр опущен).
ДБФ = Новый XBase;
// Открываем файл, разрешая запись изменений
ДБФ.ОткрытьФайл("C:\dbf_data\prices.dbf", , Ложь);
Чтобы изменить значение конкретного поля, нам сначала нужно "встать" на нужную строку. В 1С это можно сделать двумя основными способами: последовательным перебором или быстрым поиском по индексу. Разберем оба варианта.
Вариант А: Последовательный перебор записей (для небольших файлов)
Если файл содержит небольшое количество строк, мы можем обойти его в цикле, анализируя значения полей каждой записи:
ДБФ.Первая();
Пока Не ДБФ.ВКонце() Цикл
// Проверяем условие поиска
Если ДБФ.ID = ИскомыйИдентификатор Тогда
// Мы нашли нужную строку, курсор сейчас стоит на ней
Прервать;
КонецЕсли;
ДБФ.Следующая();
КонецЦикла;
Вариант Б: Быстрый поиск по индексу (для больших файлов)
Если файл DBF содержит тысячи или миллионы записей, последовательный перебор будет работать крайне медленно. В этом случае необходимо использовать индексные файлы (с расширением CDX или IDX). Давайте рассмотрим пример позиционирования с использованием метода НайтиПоКлючу():
// Указываем имя активного индекса
ДБФ.ТекущийIndex = ДБФ.Индексы.ID_Index;
// Задаем значение ключа поиска
ДБФ.Ключ.ID = ИскомыйИдентификатор;
// Выполняем поиск по точному соответствию
Если ДБФ.НайтиПоКлючу("=") Тогда
// Курсор успешно спозиционирован на найденной строке
Иначе
Сообщить("Запись с таким ключом не найдена!");
КонецЕсли;
Когда объект XBase успешно спозиционирован на нужной записи, мы можем приступить к изменению полей. Нам не нужно удалять строку! Мы можем напрямую перезаписать значение любого поля. Сделать это можно двумя способами:
Если СокрЛП(ДБФ.STATUS) = "" Тогда
ДБФ.STATUS = "ОБРАБОТАНО";
КонецЕсли;
УстановитьЗначениеПоля(). Этот метод незаменим, если имя поля передается в виде строковой переменной или содержит символы, которые нельзя использовать в качестве идентификаторов в коде 1С.
ИмяИзменяемогоПоля = "STATUS";
ДБФ.УстановитьЗначениеПоля(ИмяИзменяемогоПоля, "ОБРАБОТАНО");
Это самый важный шаг, о котором часто забывают разработчики, из-за чего изменения не сохраняются в файле на диске. Когда мы присваиваем новое значение полю (например, ДБФ.STATUS = "ОБРАБОТАНО"), эти изменения происходят во внутреннем буфере оперативной памяти 1С. Чтобы принудительно записать измененную строку обратно в физический файл на диске, необходимо обязательно вызвать метод Записать().
ДБФ.Записать();
Альтернативным вариантом является использование свойства автоматического сохранения:
ДБФ.Автосохранение = Истина;
Если это свойство установлено в значение Истина, то при переходе на другую запись или при закрытии файла изменения будут автоматически записываться на диск. Однако на практике явный вызов метода Записать() считается более надежным и контролируемым подходом.
После того как все необходимые изменения внесены и зафиксированы, файл необходимо закрыть. Это освобождает дескриптор файла в операционной системе, позволяя другим программам беспрепятственно работать с этим файлом.
ДБФ.ЗакрытьФайл();
Объединим все шаги в единый готовый алгоритм. Рассмотрим пример, в котором мы ищем в DBF-файле строку по идентификатору товара, проверяем, заполнено ли поле цены, и если оно пустое или равно нулю, устанавливаем новое значение.
ПутьКФайлу = "C:\dbf_data\goods.dbf";
ИскомыйКод = "00005432";
НоваяЦена = 1550.50;
ДБФ = Новый XBase;
Попытка
// Открываем файл с возможностью модификации данных
ДБФ.ОткрытьФайл(ПутьКФайлу, , Ложь);
Исключение
Сообщить("Не удалось открыть DBF-файл. Возможно, он заблокирован другим процессом.");
Возврат;
КонецПопытки;
// Позиционируемся на начало файла
ДБФ.Первая();
ЗаписьНайдена = Ложь;
Пока Не ДБФ.ВКонце() Цикл
// Проверяем, соответствует ли текущая запись искомому коду
Если СокрЛП(ДБФ.CODE) = ИскомыйКод Тогда
ЗаписьНайдена = Истина;
// Проверяем текущее значение поля PRICE
Если ДБФ.PRICE = 0 Или СокрЛП(ДБФ.PRICE) = "" Тогда
// Модифицируем значение непосредственно в найденной строке
ДБФ.PRICE = НоваяЦена;
// Важно: записываем изменения в файл
ДБФ.Записать();
Сообщить("Значение поля PRICE успешно обновлено для кода: " + ИскомыйКод);
Иначе
Сообщить("Поле PRICE уже заполнено и не требует обновления.");
КонецЕсли;
// Прерываем цикл, так как нужная запись найдена и обработана
Прервать;
КонецЕсли;
// Переходим к следующей строке DBF-таблицы
ДБФ.Следующая();
КонецЦикла;
Если Не ЗаписьНайдена Тогда
Сообщить("Запись с кодом " + ИскомыйКод + " не найдена в файле.");
EndЕсли;
// Обязательно закрываем файл после завершения работы
ДБФ.ЗакрытьФайл();
Если вам необходимо производить массовые изменения в больших файлах DBF, отличной альтернативой стандартному механизму XBase является использование технологии ADO (ActiveX Data Objects). Это позволяет отправлять к файлу DBF полноценные SQL-запросы типа UPDATE, что работает значительно быстрее последовательного перебора.
Проанализируем пример кода обновления полей через ADO-подключение:
// Создаем подключение ADO
Connection = Новый COMОбъект("ADODB.Connection");
Command = Новый COMОбъект("ADODB.Command");
// Строка подключения к папке с DBF-файлами (используем VFPOLEDB драйвер)
СтрокаПодключения = "Provider=VFPOLEDB.1;Data Source=C:\dbf_data\;Mode=ReadWrite;";
Попытка
Connection.Open(СтрокаПодключения);
Command.ActiveConnection = Connection;
// Формируем SQL-запрос для обновления данных
// Обратите внимание: в качестве имени таблицы выступает имя файла без расширения
Command.CommandText = "UPDATE goods SET PRICE = 1550.50 WHERE CODE = '00005432' AND (PRICE = 0 OR PRICE IS NULL)";
// Выполняем запрос
Command.Execute();
Сообщить("Данные успешно обновлены через ADO SQL.");
Connection.Close();
Исключение
Сообщить("Ошибка при работе с ADO: " + ОписаниеОшибки());
КонецПопытки;
Использование ADO идеально подходит для сложных выборок и пакетных обновлений. Однако для простой точечной перезаписи полей в небольших файлах стандартный объект 1С XBase остается наиболее простым, переносимым и надежным инструментом.