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