Форум 1С
Программистам, бухгалтерам, администраторам, пользователям
Задай вопрос - получи решение проблемы
16 апр 2024, 21:27

Помогите найти отличие в 2-ух базах dbf

Автор beztrud, 05 мая 2016, 07:57

0 Пользователей и 1 гость просматривают эту тему.

beztrud

Здравствуйте! Есть две базы dbf (файл во вложении). Обе корректно отрываются чтецами dbf типа dbfnavigator и др. просмотрщиками. Но одна база (3.dbf) выгружена мною, а вторая (выгруз.dbf) выгружена сторонней программой. Пытаюсь прочитать базу выгруз.dbf следующим кодом

&НаКлиенте
Процедура ИмяФайлаНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
ДиалогОткрытия = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
ДиалогОткрытия.ПолноеИмяФайла = "";
    ДиалогОткрытия.ПредварительныйПросмотр = Истина;
Фильтр = "База данных, *.dbf|*.dbf";
ДиалогОткрытия.Фильтр = Фильтр;
ДиалогОткрытия.МножественныйВыбор = Ложь;
ДиалогОткрытия.Заголовок = "Выберите файл DBF";
Посмотреть = Новый ОписаниеОповещения("ПосмотретьФайл", ЭтотОбъект);
    ДиалогОткрытия.Показать(Посмотреть);
КонецПроцедуры

&НаКлиенте
Процедура ПосмотретьФайл(ВыбранныйФайл, ДополнительныеПараметры) Экспорт
Если ВыбранныйФайл <> Неопределено Тогда
Объект.ПутьКФайлу = ВыбранныйФайл[0];
ФайлДанных = Новый XBase;
ФайлДанных.ОткрытьФайл(Объект.ПутьКФайлу,,Истина);
КоличествоЗаписей = ФайлДанных.КоличествоЗаписей();
ФайлДанных.Первая();
Пока НЕ ФайлДанных.ВКонце() Цикл
НомерЗаписи = ФайлДанных.НомерЗаписи();
ЗначениеПоля = ФайлДанных.FIELDS[Число(НомерЗаписи)-1].Имя;
ИмяПоля = ФайлДанных.ПолучитьЗначениеПоля(ЗначениеПоля);
СТЧ = Элементы.ИмпортируемыеПоля.ТекущиеДанные;
        СТЧ = Объект.ИмпортируемыеПоля.Добавить();
СТЧ.ИмяПоля = ЗначениеПоля;
Если ТипЗнч(ИмяПоля) = Тип("Число") Тогда
СТЧ.ТипПоля = "N";
ИначеЕсли ТипЗнч(ИмяПоля) = Тип("Строка") Тогда
СТЧ.ТипПоля = "S";
КонецЕсли;
ФайлДанных.Следующая();
КонецЦикла;
ФайлДанных.ЗакрытьФайл();
Иначе
Сообщить("Файл не выбран!");
КонецЕсли; 
КонецПроцедуры

все читается корректно. А вот при открытии 3.dbf при чтении тем же кодом выскакивает ошибка, типа что индекс находиться за границами массива. Повторюсь, что обе базы прекрасно читаются просмотрщиками dbf. Никаких ошибок не возникает. Итак вопросы: 1)в чем отличие структуры этих 2-ух баз; 2) такое ощущение что в файле 3.dbf не указан "конец файла". Как правильно указать на "конец файла". Заранее спасибо.

Игорь Иванов

Википедия на что?
Описание DBF здесь.
Описание xDBF здесь. Внизу ссылка Внутренняя структура dbf-файла.
Бесплатный HEX-редактор HxD. Конец файла указан в обоих файлах.

beztrud

Так где ошибка в коде или как перехватить выход индекса за пределы массива?

Игорь Иванов

В тексте процедуры ошибки нет. Проблема, думаю, не в ней, а в файле. Возможно, в программе, с помощью которой вы его создаёте. Попробуйте добавить новые записи не в середину, а в конец исходного файла. И установите ширину полей поменьше, длинные поля трудно сравнивать визуально. В идеале пусть будут по 1 символу.
Неужели функция ВКонец() проскакивает EOF?

beztrud

Не отрабатывает ни EOF ни BOF. Копаю дальше в сторону базы 3.dbf, которая почему-то открывается сторонними чтецами. Вопрос открыт.
Добавлено: 06 мая 2016, 08:02


Всё решено проблема в строчке

ЗначениеПоля = ФайлДанных.FIELDS[Число(НомерЗаписи)-1].Имя;
ИмяПоля = ФайлДанных.ПолучитьЗначениеПоля(ЗначениеПоля);

Не надо читать поля количеством записей в базе.
Добавлено: 06 мая 2016, 08:03


Точнее сам цикл в корне неверен (бессмыслен).

Игорь Иванов

Введение.
Машина 1С работает с файлами DFF формата dBase III. Это прямо сказано в книге Профессиональная разработка в системе 1С:Предприятие 8, глава 14, пункт Работа с DBF, изд. 2006 г. (далее - Книга). Кроме того, если открыть HEX-редактором какой-либо файл dbf из 7.7, первый байт равен 03h. Описание формата xBase приведено здесь (далее - Сайт). Мы видим, что номер версии 03h означает "File without DBT". (Этот же номер версии указан и у файлов, созданных другими приложениями, например, OKEI.DBF, STREET.DBF.) Во всяком случае, это не dBase II. Эти два формата различаются подходом к символу конца файла. На Сайте об этом сказано так:
"dBASE II regards any End-of-File 1Ah value as the end of the file. dBASE III regard an End-of-File as an ordinary character, however it appends an extra End-of-File character at the physical end of the file.
If the file is packed the physical size of the file may be larger than the logical i.e. there may be garbage after the EOF mark.
"
То есть у файла формата dBase III символ конца 1Ah может встретиться и внутри файла, и быть не последним символом. (Поскольку длина таблицы не стандартизирована, в отличие, скажем, от таблиц 1С, кратных страницам 4 килобайта, упаковщик может добавлять байты после конца файла.) На Сайте приведёт пример файла dbf, в конце которого стоит два символа EOF: "1A 1A".

1. В нашем случае у обоих файлов - выгруз.DBF и 3.DBF - с концом файла всё нормально (если смотреть HEX-редактором HxD): в тексте он встречается только один раз, только последним символом.

2. Применённая в нашем случае конструкция обхода таблицы описана как в книге Описание встроенного языка 7.7, так и в синтакс-помощнике конфигуратора "восьмёрки":

  • установить указатель на первую запись,
  • цикл с предусловием на достижение символа конца файла,
  • переход к следующей записи в последней строке цикла
xB.Первая();
МаксСтоимость = 0 ;
Пока Не xB.ВКонце() Цикл
    Если xB.COST > МаксСтоимость Тогда
        МаксСтоимость = xB.COST;
    КонецЕсли;
    xB.Следующая();
КонецЦикла;

В Книге описана другая конструкция, где позиционирования на первую запись может не происходить, а цикл обеспечивается методом Следующая():
Пока БД.Следующая() Цикл
    Сообщить(БД.CODE + БД.Name);
КонецЦикла;

Попробуйте применить эту конструкцию.

3. Индексный файл cdx часто рассматривается пользователями как необязательный. Однако машина может считать по-другому. Возможно, в нашем случае при попытке открытия второго файла машина пытается использовать индексный файл, созданный ею для предыдущего файла. (Хотя файл dbf мы закрыли, индексного это не касалось.)
Попробуйте открывать файлы в обратном порядке: сначала 3, потом выгруз.

beztrud

Тут всё проще. Сам облажался; 1С не причем. Пытался получить имена полей БД перебирая их общим количеством записей в БД. Это равносильно мерить рост трамвайными остановками :D. Вот код который верно работает:

&НаКлиенте
Процедура ИмяФайлаНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
Объект.ИмпортируемыеПоля.Очистить();
ДиалогОткрытия = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
ДиалогОткрытия.ПолноеИмяФайла = "";
    ДиалогОткрытия.ПредварительныйПросмотр = Истина;
Фильтр = "База данных, *.dbf|*.dbf";
ДиалогОткрытия.Фильтр = Фильтр;
ДиалогОткрытия.МножественныйВыбор = Ложь;
ДиалогОткрытия.Заголовок = "Выберите файл DBF";
Посмотреть = Новый ОписаниеОповещения("ПосмотретьФайл", ЭтотОбъект);
    ДиалогОткрытия.Показать(Посмотреть);
КонецПроцедуры

&НаКлиенте
Процедура ПосмотретьФайл(ВыбранныйФайл, ДополнительныеПараметры) Экспорт
Если ВыбранныйФайл <> Неопределено Тогда
Объект.ПутьКФайлу = ВыбранныйФайл[0];
ФайлДанных = Новый XBase;
ФайлДанных.ОткрытьФайл(Строка(Объект.ПутьКФайлу),"",Истина);
КоличествоПолей = ФайлДанных.поля.Количество();
ФайлДанных.Первая();
Для СтрокаПоля=0 По КоличествоПолей-1 Цикл
ЗначениеПоля = ФайлДанных.FIELDS[СтрокаПоля].Имя;
ИмяПоля = ФайлДанных.ПолучитьЗначениеПоля(ЗначениеПоля);
СТЧ = Элементы.ИмпортируемыеПоля.ТекущиеДанные;
СТЧ = Объект.ИмпортируемыеПоля.Добавить();
СТЧ.ИмяПоля = ЗначениеПоля;
ДлинаПоля = ФайлДанных.FIELDS[СтрокаПоля].Длина;
ТочностьПоля = ФайлДанных.FIELDS[СтрокаПоля].Точность;
Если ТипЗнч(ИмяПоля) = Тип("Число") Тогда
СТЧ.ТипПоля = "N";
Если ТочностьПоля = 0 Тогда
СТЧ.ДлинаПоля = ДлинаПоля;
Иначе
СТЧ.ДлинаПоля = Строка(ДлинаПоля)+"."+Строка(ТочностьПоля);
КонецЕсли;
ИначеЕсли ТипЗнч(ИмяПоля) = Тип("Строка") Тогда
СТЧ.ТипПоля = "S";
СТЧ.ДлинаПоля = ДлинаПоля;
КонецЕсли;
ФайлДанных.Следующая();
КонецЦикла;

ФайлДанных.ЗакрытьФайл();
Иначе
Сообщить("Файл не выбран!");
КонецЕсли; 
КонецПроцедуры


Добавлено: 06 мая 2016, 11:28


А база выгруз.дбф читалась только потому, что количество полей соответствовала количеству записей в БД. Вопрос закрыт.

Теги:

Похожие темы (5)

Рейтинг@Mail.ru

Поиск