Всем, кто когда-либо встречался с программированием в среде 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", "|"); КонецПроцедуры