1С 7.7: Работаем с DBF файлами красиво!

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

Понятно что все отличая работы с разными базами заключаеются в различаи из внутренних структур, а следовательно унифицировать нужно именно этот процесс. Для этого напишем небольшую функцию, которая будет аналогом функции Split во многих языках программирования.

Функция Поле(Стр, Разделитель, Позиция) Экспорт
//Позиция начинается с единицы, например
//Поле("Вася|Люба", "|", 1) ="Вася" 
     Если Позиция < 1 Тогда Возврат Стр; КонецЕсли; 
     Поз = 0; Значение = ""; 
     Если СтрЧислоВхождений(Стр, Разделитель) = 0 Тогда 
          Возврат Стр; 
     ИначеЕсли СтрЧислоВхождений(Стр, Разделитель) + 1 < Позиция Тогда 
          Возврат ""; 
     КонецЕсли; 
     Для ы = 1 По СтрДлина(Стр) Цикл 
          Значение = Значение + Сред(Стр, ы, 1); 
          Если Сред(Стр, ы, 1) = Разделитель Тогда 
               Поз = Поз + 1; 
               Если Поз = Число(Позиция) Тогда
                    Возврат Лев(Значение, СтрДлина(Значение)-1); 
               Иначе Значение = ""; 
               КонецЕсли; 
         КонецЕсли; 
     КонецЦикла; 
     Возврат Значение; 
КонецФункции

Ну вот собственно практически и все. Дальше нужно написать функции работы с DBF файлами, применяя в них стандартные функции и процедуры 1С, так что бы процесс работы с DBF файлами не приносил больше лишних трудностей и не загромождал код отчета.

Процедура СоздатьDBFФайл(ИмяФайла, Поля, Индексы) Экспорт 
// "Поля", "Индексы" - Строка заданного формата, содержащая все пункты 
//функции "ДобавитьПоле" или "ДобавитьИндекс" 
//В качестве разделителя полей используется символ '|', в качестве 
//разделителя параметров символ '#' 
//Например:
//СоздатьDBFФайл("Base.dbf", "ID#N#5#0|FIO#C#255#", "IDXID#ID#1#0#"); 

     БД = СоздатьОбъект("XBASE"); 
     КонтрольОшибок = 0; 
     //Создаем поля---------------------------> 
     Разделитель = "|"; РазделительПараметров = "#"; 
     Для ы = 1 По СтрЧислоВхождений(Поля, Разделитель)+1 Цикл 
     ТекущееПоле = Поле(Поля, Разделитель, ы); 
     Если ПустаяСтрока(ТекущееПоле) = 1 Тогда Продолжить; 
     ИначеЕсли
          СтрЧислоВхождений(ТекущееПоле, РазделительПараметров) <> 3 
     Тогда
          Предупреждение("Неверное число параметров!");
          КонтрольОшибок = КонтрольОшибок + 1; 
          Продолжить; 
     КонецЕсли; 
     ИмяПоля = Поле(ТекущееПоле, РазделительПараметров, 1); 
     ТипПоля = Поле(ТекущееПоле, РазделительПараметров, 2); 
     ДлинаПоля = Поле(ТекущееПоле, РазделительПараметров, 3); 
     ТочностьПоля = Поле(ТекущееПоле, РазделительПараметров, 4); 
     Если (ПустаяСтрока(ИмяПоля) = 1) или
            (ПустаяСтрока(ТипПоля) = 1) Тогда 
          Предупреждение("Параметры 'Имя поля' и 'Тип поля'
должны быть заполнены!"); 
          КонтрольОшибок = КонтрольОшибок + 1; 
          Продолжить; 
     КонецЕсли; 
     Попытка 
          ПроверкаНаЧисло = Число(ДлинаПоля);
          ПроверкаНаЧисло = Число(ТочностьПоля); 
     Исключение 
          Предупреждение("Параметры 'Длина поля' и 'Точность поля'
 должны быть числовыми!"); 
          КонтрольОшибок = КонтрольОшибок + 1; 
          Продолжить; 
     КонецПопытки; 
     БД.ДобавитьПоле(ИмяПоля, ТипПоля, ДлинаПоля, ТочностьПоля); 
     КонецЦикла; 
     Для ы = 1 По СтрЧислоВхождений(Индексы, Разделитель)+1 Цикл 
     ТекущееПоле = Поле(Индексы, Разделитель, ы); 
     Если ПустаяСтрока(ТекущееПоле) = 1 Тогда Продолжить; 
     ИначеЕсли
          СтрЧислоВхождений(ТекущееПоле, РазделительПараметров) <> 4 
     Тогда Предупреждение("Неверное число параметров!"); 
          КонтрольОшибок = КонтрольОшибок + 1; 
          Продолжить; 
     КонецЕсли; 
     ИмяПоля = Поле(ТекущееПоле, РазделительПараметров, 1); 
     ВыражениеПоля = Поле(ТекущееПоле, РазделительПараметров, 2); 
     УникальностьПоля = Поле(ТекущееПоле, РазделительПараметров, 3); 
     УбываниеПоля = Поле(ТекущееПоле, РазделительПараметров, 4); 
     ФильтрПоля = Поле(ТекущееПоле, РазделительПараметров, 5); 
     Если (ПустаяСтрока(ИмяПоля) = 1) или
            (ПустаяСтрока(ВыражениеПоля) = 1) 
     Тогда 
           Предупреждение("Параметры 'Имя индекса' и 'Выражение индекса' 
должны быть заполнены!"); 
          КонтрольОшибок = КонтрольОшибок + 1; 
          Продолжить; 
     КонецЕсли; 
     Если (Число(УникальностьПоля) <> 0) и
            (Число(УникальностьПоля) <> 1) 
    Тогда 
         Предупреждение("Параметр 'Уникальность' должен
быть равен 0 и 1!"); 
         КонтрольОшибок = КонтрольОшибок + 1; 
         Продолжить; 
    КонецЕсли; 
    Попытка 
         Если (Число(УбываниеПоля) <> 0) и
                 (Число(УбываниеПоля) <> 1) Тогда 
               Предупреждение("Параметр 'Убывание' должен
быть равен 0 и 1!"); 
               Продолжить; 
          КонецЕсли; 
     Исключение 
          Предупреждение("Параметры должны быть числовыми!"); 
          Продолжить; 
     КонецПопытки; 
     БД.ДобавитьИндекс(ИмяПоля, ВыражениеПоля, УникальностьПоля, 
          УбываниеПоля, ФильтрПоля); 
      КонецЦикла; 
      //Создаем поля---------------------------< 
      Если КонтрольОшибок = 0 Тогда 
           БД.СоздатьФайл(СокрЛП(ИмяФайла)+".dbf",
                                   СокрЛП(ИмяФайла)+".cdx"); 
           Сообщить("Файл "+СокрЛП(ИмяФайла)+".dbf успешно создан."); 
      Иначе 
           Предупреждение("Файл базы данных не создан!
Необходимо исправить "+КонтрольОшибок+" ошибок!"); 
      КонецЕсли; 
      БД.ЗакрытьФайл(); 
КонецПроцедуры

//********************************************************************

Процедура ДобавитьЗаписьВDDBFФайл(ИмяФайла, Поля, Значения,
Разделитель, Информировать) Экспорт 
//'Поля','Значения' - через 'разделитель' по порядядку слева направо 
      Если (ФС.СуществуетФайл(СокрЛП(ИмяФайла)) = 0) и 
             (ФС.СуществуетФайл(СокрЛП(ИмяФайла + ".dbf")) = 0) Тогда 
                Предупреждение("Файл "+ИмяФайла+" не найден!"); 
                Возврат; 
      КонецЕсли; 
      Если СтрЧислоВхождений(Значения, Разделитель) <> 
             СтрЧислоВхождений(Поля, Разделитель) Тогда 
           Предупреждение("Число значений и полей различны!"); 
           Возврат; 
      КонецЕсли; 
      Если Поле(ИмяФайла, ".", 2) = "dbf" Тогда 
            ИмяФайла = Поле(ИмяФайла, ".", 1); 
      КонецЕсли;      
      БД = СоздатьОбъект("XBASE"); 
      БД.ОткрытьФайл(ИмяФайла); 
      //Пишем данные в базу-----------------> 
      Попытка 
      БД.Добавить(); 
      Для ы = 1 По СтрЧислоВхождений(Значения, Разделитель)+1 Цикл 
           БД.УстановитьЗначениеПоля(Поле(Поля, Разделитель, ы),
                                                    Поле(Значения,
                                                    Разделитель, ы)); 
      КонецЦикла; 
      БД.Записать(); 
      БД.Переиндексировать(); 
      Исключение 
           Предупреждение("Ошибка при добавлении в базу данных!
Возможно база используется другим приложением!"); 
      КонецПопытки; 
      //Пишем данные в базу-----------------< 
      БД.ЗакрытьФайл(); 
      Если Информировать = 1 Тогда Сообщить("В базу "+СокрЛП(ИмяФайла)+" 
успешно занесены новые данные.");
     КонецЕсли; 
КонецПроцедуры

//********************************************************************

Функция УдалитьВDBFФайлеПоЗначениюПоля(ИмяФайла,
ИмяПоля, Значение, Разделитель) Экспорт
//ПоляНаВывод - Какие поля выводить, Имена столбцов через разделитель 
      Если (ФС.СуществуетФайл(СокрЛП(ИмяФайла)) = 0) и 
             (ФС.СуществуетФайл(СокрЛП(ИмяФайла + ".dbf")) = 0) Тогда 
                Предупреждение("Файл "+ИмяФайла+" не найден!"); 
                Возврат; 
      КонецЕсли; 
      Если ПустаяСтрока(ИмяПоля) = 1 Тогда 
           Предупреждение("Укажите поле!"); 
           Возврат ""; 
      КонецЕсли; 
      Если Поле(ИмяФайла, ".", 2) = "dbf" Тогда 
           ИмяФайла = Поле(ИмяФайла, ".", 1); 
      КонецЕсли; 
      БД = СоздатьОбъект("XBASE"); 
      Если ФС.СуществуетФайл(ИмяФайла+".cdx") = 0 Тогда 
           БД.ОткрытьФайл(ИмяФайла+".dbf"); 
      Иначе 
           БД.ОткрытьФайл(ИмяФайла+".dbf", ИмяФайла+".cdx"); 
      КонецЕсли; 
      Для й = 1 По БД.КоличествоЗаписей() Цикл 
      Попытка 
           Если СокрЛП(БД.ПолучитьЗначениеПоля(ИмяПоля)) =
                  СокрЛП(Значение) Тогда 
                БД.Удалить(); 
           КонецЕсли; 
      Исключение 
           Предупреждение("Ошибка обработки данных!"); 
           БД.ЗакрытьФайл();           
           Возврат ""; 
      КонецПопытки; 
      БД.Следующая(); 
      КонецЦикла; 
      БД.Сжать(); 
      БД.ЗакрытьФайл();
      Возврат 1;
КонецФункции

//********************************************************************

Функция НайтиВDBFФайлеПоЗначениюПоля(ИмяФайла, ИмяПоля,
Значение, ПоляНаВывод, Разделитель) Экспорт 
//ПоляНаВывод - Какие поля выводить, Имена столбцов через разделитель 
     Если (ФС.СуществуетФайл(СокрЛП(ИмяФайла)) = 0) и 
            (ФС.СуществуетФайл(СокрЛП(ИмяФайла + ".dbf")) = 0) Тогда 
                 Предупреждение("Файл "+ИмяФайла+" не найден!"); 
                 Возврат ""; 
     КонецЕсли; 
         Если ПустаяСтрока(ИмяПоля) = 1 Тогда 
             Предупреждение("Укажите поле!"); 
             Возврат ""; 
         КонецЕсли; 
     Если Поле(ИмяФайла, ".", 2) = "dbf" Тогда 
         ИмяФайла = Поле(ИмяФайла, ".", 1); 
     КонецЕсли; 
     БД = СоздатьОбъект("XBASE"); 
     Если ФС.СуществуетФайл(ИмяФайла+".cdx") = 0 Тогда 
         БД.ОткрытьФайл(ИмяФайла+".dbf"); 
     Иначе 
         БД.ОткрытьФайл(ИмяФайла+".dbf", ИмяФайла+".cdx"); 
     КонецЕсли;
     РезультатРаботыФункции = СоздатьОбъект("СписокЗначений"); 
     Найдено = 0; 
     БД.Сжать(); 
     БД.Первая(); 
     Для й = 1 По БД.КоличествоЗаписей() Цикл 
         Попытка 
             Если СокрЛП(БД.ПолучитьЗначениеПоля(ИмяПоля)) =
                    СокрЛП(Значение) Тогда 
             Результат = ""; 
             Для ы = 1 по СтрЧислоВхождений(ПоляНаВывод, Разделитель)+1
             Цикл 
                 Результат = Результат + 
                    СокрЛП(БД.ПолучитьЗначениеПоля(Поле(ПоляНаВывод, 
                                Разделитель, ы))) + "|"; 
             КонецЦикла; 
             Найдено = Найдено + 1; 
                 РезультатРаботыФункции.ДобавитьЗначение(Найдено,
                                                     Результат); 
             КонецЕсли; 
         Исключение 
             Предупреждение("Ошибка обработки данных!"); 
             БД.ЗакрытьФайл(); 
             Возврат ""; 
         КонецПопытки; 
         БД.Следующая(); 
     КонецЦикла; 
     БД.ЗакрытьФайл(); 
     Возврат РезультатРаботыФункции; 
КонецФункции

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

Процедура ТЕСТ() 

 //Example Code 
  
     ИФ = "Test"; 
     ИБ = "Test.dbf"; 

     СоздатьDBFФайл(ИФ, "ID#N#5#0|FIO#C#255#|AGE#N#2#0",
                             "IDXID#ID#1#0#"); 
     ДобавитьЗаписьВDDBFФайл(ИБ, "ID|FIO|AGE", "1|Вася|45", "|", 0); 
     ДобавитьЗаписьВDDBFФайл(ИБ, "ID|FIO|AGE", "2|Петя|44", "|", 0); 
     ДобавитьЗаписьВDDBFФайл(ИБ, "ID|FIO|AGE", "3|Ваня|20", "|", 0); 
     ДобавитьЗаписьВDDBFФайл(ИБ, "ID|FIO|AGE", "4|Юля|34", "|", 0); 
     ДобавитьЗаписьВDDBFФайл(ИБ, "ID|FIO|AGE", "5|Петя|11", "|", 0); 
  
     Результат = НайтиВDBFФайлеПоЗначениюПоля(ИБ, "FIO", "Петя",
                      "FIO|AGE", "|"); 
     Если ПустаяСтрока(Результат) = 0 Тогда 
         Для ы = 1 по Результат.РазмерСписка() Цикл 
             Стр = ""; 
             Результат.ПолучитьЗначение(ы, Стр); 
             Сообщить(Стр); 
         КонецЦикла; 
     КонецЕсли; 
    УдалитьВDBFФайлеПоЗначениюПоля(ИБ, "AGE", "34", "|"); 
КонецПроцедуры

Запись опубликована в рубрике с метками , . Добавьте в закладки постоянную ссылку.