DBF-файлы (XBase)

Опубликовано Опубликовано в рубрике 1C Программирование, Разное

Сразу оговорюсь статья не моя, вот честная ссылка на автора:

Автор статьи: Волшебник | Редакторы: kiruha
Последняя редакция №3 от 01.12.06 | История
URL: http://kb.mista.ru/article.php?id=190

Чтение файла DBF

Файл = создатьОбъект("XBASE"); //создаем ссылку на файл DBF
Файл.ОткрытьФайл("catalog.dbf"); //открываем файл на диске
Файл.КодоваяСтраница(1); //задаем кодировку: 0 - windows, 1 - DOS
Если Файл.Открыта()=0 Тогда //проверяем, удалось ли открыть файл
        Сообщить("Не удалось открыть файл!");
КонецЕсли;
Файл.Первая(); //позиционируемся на первой записи
Пока Файл.ВКонце()=0 Цикл //пока не дошли до конца, крутим цикл
      НомерЗаписи = Файл.НомерЗаписи(); //получаем номер текущей записи
      НазвТовара = Файл.NAME; //получаем значение поля
      Цена = Файл.ПолучитьЗначениеПоля("PRICE"); //так тоже можно, но чуть медленнее
      Файл.Следующая(); //переходим на следующую запись
КонецЦикла;
Файл.Последняя(); //позиционируемся на последней записи
Пока Файл.ВНачале()=0 Цикл //пока не дошли до начала, крутим цикл
       НазвТовара = Файл.NAME;
       Цена = Файл.PRICE;
       Файл. Предыдущая(); //переходим на предыдущую запись
КонецЦикла;
Для н = 1 По Файл.КоличествоЗаписей() Цикл //здесь все понятно, по-моему
      Файл.Перейти(н); //позиционируемся на определенной записи
       НазвТовара = Файл.NAME;
       Цена = Файл.PRICE;
КонецЦикла;
Файл.ЗакрытьФайл(); //не забывайте пожалуйста

Запись в файл DBF

Файл = создатьОбъект("XBASE"); //создаем ссылку на файл DBF
//определяем структуру файла
//Синтаксис: ДобавитьПоле(<Название>,<Тип>,<Длина>,<Точность>)
Файл.ДобавитьПоле("NAME","S",50,0);
Файл.ДобавитьПоле("PRICE","N",10,2);
Файл.СоздатьФайл("catalog.dbf"); //создаем файл физически
СпрТовары.ВыбратьЭлементы();
Пока СпрТовары.ПолучитьЭлемент()=1 Цикл
       Файл.Добавить();
       Файл.NAME = СпрТовары.Наименование;
       Файл.УстановитьЗначениеПоля("PRICE",СпрТовары.Цена) //так тоже можно;
       Файл.Записать();
КонецЦикла;
Файл.ЗакрытьФайл(); //не забывайте пожалуйста

Работа со структурой файла DBF
Например, создадим файл, идентичный по структуре исходному.

//При этом применяется метод ОписаниеПоля, который возвращает характеристики поля с указанным номером 
//синтаксис: ОписаниеПоля(<НомерПоля>,<НазваниеПоля>,<Тип>,<Длина>,<Точность>) 
Файл1 = СоздатьОбъект("XBASE");
Файл2 = СоздатьОбъект("XBASE");
Файл1 = ОткрытьФайл("file1.dbf");
Для н = 1 По Файл1.КоличествоПолей() Цикл
        НазвПоля = "";
        Тип = "";
        Длина = 0;
        Точность = 0;
        Файл1.ОписаниеПоля(н,назвПоля,Тип,Длина,Точность);
        Файл2.ДобавитьПоле(назвПоля,Тип,Длина,Точность);
КонецЦикла;
Для работы с файлом DBF неизвестной структуры часто применяются следующие методы: 
ПолучитьЗначениеПоля(<ИмяПоля>); 
УстановитьЗначениеПоля(<ИмяПоля>,<значение>);

Работа с удаленными записями
Файлы DBF устроены таким образом, что удаление записи не приводит к физическому удалению записи из файла. Запись просто помечается на удаление и пропускается при переборе. Таким образом размер файла остается прежним. Чтобы физически удалить все помеченные на удаление записи нужно применить метод Сжать. Средства встроенного языка позволяют работать с такими записями, перебирать их и даже отменять пометку на удаление.

Файл.ПоказыватьУдаленные(1);
Файл.Первая();
Пока Файл.ВКонце()=0 Цикл
      Если Файл.ЗаписьУдалена()=1 Тогда
            Файл.Восстановить();
      КонецЕсли;
      Файл.Следующая();
КонецЦикла;
Файл.Первая();
Пока Файл.ВКонце()=0 Цикл
      Если Файл.PRICE < 1000 Тогда
            Файл.Удалить();
      КонецЕсли;
      Файл.Следующая();
КонецЦикла;
Файл.Сжать(); //удалить записи физически
//Можно удалить все записи в файле одним движением. 
//При этом они физически удаляются и не могут быть восстановлены. 
Файл.ОчиститьВсе();

Стоит еще отметить про метод Очистить(), что он очищает все поля текущей записи. Атрибуты, соответствующие полям типа «строковый» приобретают значение «пустая строка», числовой — 0, логический — 0, дата — «пустая дата».
Работа с индексами

Для организации упорядочивания содержимого файла БД и поиска в ней по значению одного или нескольких полей применяется механизм индексов. Его применение можно сравнить с сортировкой картотеки по определенному признаку (совокупности признаков). Однако, в отличие от картотеки, файл БД может иметь сразу несколько индексов, и, соответственно, являться упорядоченным одновременно по нескольким признакам. Индексы хранятся в индексном файле. Индексный файл может содержать информацию более чем об одном индексе. Рекомендуется для одного файла DBF иметь один индексный файл, в котором хранятся все индексы для этого файла.

Каждый индекс имеет наименование, признак уникальности, выражение индекса и фильтр. Наименование индекса используется для идентификации индекса. Выражение индекса и фильтр представляют собой написанные на специальном языке выражения, вычисление значения которых для каждой записи позволяет определить ее место при упорядочивании и необходимость помещения ее в упорядоченный список (индекс может содержать упоминание не обо всех записях таблицы, а только об удовлетворяющих выражению фильтра). Уникальный индекс (имеющий установленным признак уникальности) позволяет иметь в индексе ссылки на записи только с различным значением индексного выражения.

Основное правило: индекс нужен, чтобы быстро искать нужную запись.
DBF-ФАЙЛ

1    Иванов
2    Абдулов
3    Барабанов
4    Мирнов
5    Раскольников
6    Комаров

Индексный файл

   
Абдулов       2
Барабанов     3
Иванов        1
Мирнов        4
Комаров       6
Раскольников  5

Нужно быстро найти Комаров. В неупорядоченном исходном файле искать его можно только последовательным перебором всех записей, что будет очень долго при большом числе записей. В индексе найти Комарова можно очень быстро, поскольку индекс отсортирован по полю Фамилия. При этом мы узнаем физический номер записи в файле DBF и производим прямое позиционирование на нужную запись.
После создания структуры базы данных можно добавить индексы следующим образом:

//Синтаксис: ДобавитьИндекс(<Название>, <Выражение>, <Уникальность>, <Убывание>, <Фильтр>) 
Файл = СоздатьОбъект("XBase");
Файл.ДобавитьПоле("NAME", 1, 19, 3);
Файл.ДобавитьПоле("PRICE", 2, 25, 0);
Файл.ДобавитьИндекс("IDXCODE", "CODE", 1, 0, "");
Файл.ДобавитьИндекс("IDXNAME", "NAME", 0, 0, "");
Файл.ДобавитьИндекс("IDXNAMECODE", "NAME+CODE", 0, 0, "");
Файл.СоздатьФайл("mydb.dbf", "mydb.cdx");
//1-й вариант
Файл.ТекущийИндекс("IDXNAME");
Файл.Найти("Иванов",0); //передается значение и режим поиска
//2-й вариант
Файл.ТекущийИндекс("IDXNAMECODE");
Файл.Ключ.NAME = "Иванов";
Файл.Ключ.CODE = 123;
Файл.НайтиПоКлючу(0);

После сбоя рекомендуется заново переформировать все индексы

Файл.Переиндексировать();

В 1С существует специальный язык для задания выражений и фильтра индекса. Подробнее о нем, смотрите в документации на встроенный язык. Отбор по значению поля. Часто возникают вопросы по фильтрации файла БД по значению определенного поля. Предположим, что в предыдущем примере сотрудники работают в разных подразделениях «Офис» и «Филиал», и нужно вывести всех сотрудников работающих в офисе. Нетрудно увидеть, что в языке нет явных способов получить записи по фильтру, но имея индекс тем не менее, данную операцию можно эффективно (без перебора всех записей) осуществить.

1. Создадим файл индекса, если он ранее не был создан

ФайлИндекс= "mydb.cdx";
ФайлБазы="mydb.dbf";
Если ФС.СуществуетФайл(ФайлИндекс) <> 1 Тогда
        Файл.ДобавитьИндекс("INDOtdel", "Otdel", 0, 0, "");
        Файл.СоздатьИндексныйФайл(ФайлИндекс);    
КонецЕсли;

2. Откроем Файл базы с индексом

Если Файл.Открыта() = 1 Тогда
 Файл.ЗакрытьФайл();
 Файл.ОткрытьФайл(ФайлБазы, ФайлИндекс, 1);
КонецЕсли;

3.Прейдем на первую запись

Файл.ТекущийИндекс("INDOtdel"); // Установили текущий индекс - "по отделам"
Файл.Найти("Офис",0);           //перешли на первую запись

4. И так как все записи упорядочены по индексу — достаточно пройтись
по записям, пока не встретится запись с другим значением поля «Otdel» :

Пока Файл.ВКонце() = 0 Цикл
   Если СокрЛП(Файл.Otdel)<>«Офис» Тогда
               прервать
   КонецЕсли;
   Сообщить(Файл.NAME);
   Файл.Следующая();
КонецЦикла;

Более подробно см. типовую — работа с адресным классификатором