3 / 0 / 0
Регистрация: 06.06.2012
Сообщений: 16
1

Импорт DBF в Oracle

02.10.2013, 11:10. Показов 11299. Ответов 27
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Коллеги, добрый день.

Есть следующая задача:
создать клиент, который будет переодически грузить DBF-файл (КЛАДР), с определенного локального диска в таблицу на Oracle. Версия Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production.
На Delphi есть ODAC.

Каким иснтрументом для этих целей лучше всего воспользоваться? Какой порядок.
Таблички большие поэтому предвижу проблемы со скоростью.
Миграцией до этого особо не занимался, прошу подсказть.
Ссылки на поиск прошу не кидать.

Заранее спасибо за ответы.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
02.10.2013, 11:10
Ответы с готовыми решениями:

Импорт dbf в dbgrid
добрый день. имеется следующий код, ADOQuery1.SQL.Clear; ADOQuery1.SQL.Add('SELECT * FROM...

Импорт Данных из dbf в DBGrid
Всем добрый день! Необходимо по работе написать приложение для выгрузки данных из dbf. Никогда не...

Какими средствами Oracle экспортировать данные из таблицы Oracle в dbf-файл?
Здравствуйте! Не подскажите чайнику какими средствами Oracle экспортировать данные из таблицы...

Импорт DBF файла
Ребята как мне импортировать DBF файл в Oracle9i Data Base, или где мне найти документацию по этой...

27
4172 / 1822 / 218
Регистрация: 06.10.2010
Сообщений: 4,093
03.10.2013, 13:50 2
Формат dbf довольно простой - с ним можно работать напрямую. Я делал так:
1) Объявляю динамический массив
Delphi
1
2
3
4
table: array of record
                deleted: AnsiChar; //обязательное поле для всех таблиц
                //тут описываются поля таблицы
                end;
2) Проецирую таблицу на массив через MapViewOfFile
3) Теперь можно работать с DBF-файлом как с массивом

Скорость при таком подходе очень даже приемлемая, код довольно прост и понятен.
2
13105 / 5886 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
04.10.2013, 01:04 3
Здесь лучше использовать компоненты, специально предназначенные для работы с БД. Например, можно использовать TADOQuery. На форму надо положить 2 TADOQuery - ADOQuery1 и ADOQuery2. ADOQuery1 связать с DBF файлом, ADOQuery2 - связать с таблицей Oracle. ADOQuery1 в режиме просмотра - Browse (это предустановленный режим). Для ADOQuery2 установить свойство: CashedUpdates := True.
Обработка будет заключаться в следующем. Открываем ADOQuery1. В цикле делаем следующее. ADOQuery2 переводим в режим Insert (ADOQuery2.Insert), читаем записи из ADOQuery1 и записываем их в ADOQuery2. Через каждые, скажем, 500 обработанных записей, выполняем запись в целевую базу через вызов ADOQuery2.ApplyUpdates(0). Затем, опять переводим ADOQuery2 в режим вставки ADOQuery2.Insert. Записываем в ADOQuery2 следующие 500 записей и записываем их в БД - ADOQuery2.ApplyUpdates(0). И т. д., до момента, когда будут записаны все записи, взятые из ADOQuery1.

Для настройки ADOQuery1 и ADOQuery2, следует сформировать для них строки соединения - ConnectionString. Шаблоны ConnectionString для DBF и Oracle можно взять отсюда: http://www.connectionstrings.com: DBF / FoxPro, Oracle.
2
3176 / 1935 / 312
Регистрация: 27.08.2010
Сообщений: 5,131
Записей в блоге: 1
04.10.2013, 01:46 4
Цитата Сообщение от murderer Посмотреть сообщение
Теперь можно работать с DBF-файлом как с массивом
Поддержу. Если требуется только чтение из DB - ничего лучше не придумать.
0
13105 / 5886 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
04.10.2013, 02:29 5
Отображать файл - это может быть интересней. Но использовать стандартный подход со специальными компонентами - это технологично.
0
3176 / 1935 / 312
Регистрация: 27.08.2010
Сообщений: 5,131
Записей в блоге: 1
04.10.2013, 03:51 6
Цитата Сообщение от Mawrat Посмотреть сообщение
со специальными компонентами - это технологично
Если речь идет о доступе только-на-чтение - то нет.

DBF-файл, по своему устройству, является массивом записей. Обращаться к массиву в памяти "технологичнее", чем по индексу (как предложено murderer), уже невозможно.

В лучшем случае, и если только "специальный компонент" поддерживает режим R/O (или In Memory DB), удастся получить сравнимую скорость.

+ экономия на отсутствии всяких generic wrappers и прямом доступе к нужным полям записи.

Лет десять назад, когда .DBF попадался почаще, у меня примерно так была устроена работа с бывшей Clipper-базой + собственная реализация индексов (B*-Tree) - по скорости выигрывал у Clipper примерно вдвое.
0
13105 / 5886 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
04.10.2013, 09:41 7
Цитата Сообщение от gazlan Посмотреть сообщение
Обращаться к массиву в памяти "технологичнее", чем по индексу (как предложено murderer), уже невозможно.
Мы работаем с БД и вдруг:
Цитата Сообщение от gazlan Посмотреть сообщение
Обращаться к массиву в памяти...
Здесь наблюдается нарушение общности в организации доступа к данным. Исходные данные - это массив, а целевые - таблица БД. Соответственно, такой ход нарушит единообразие в архитектуре приложения (или группы приложений). Именно в этом я вижу основную причину "не технологичности". Кроме этого, потребуется предварительно точно описать структуру исходных данных - типы и порядок следования.

Что касается технической стороны вопроса - здесь спору нет, решение, которое предложил murderer, будет наилучшим по скорости обработки . Но по архитектурно-технологическим параметрам оно может быть неприемлемым.

Добавлено через 10 минут
Замечу ещё раз - спор здесь только по вопросам архитектуры. Что касается постов murderer в разных темах - они очень полезные. Ведущая идеология в его походе - это оптимальность решения конкретной (возможно - изолированной) задачи.
0
3176 / 1935 / 312
Регистрация: 27.08.2010
Сообщений: 5,131
Записей в блоге: 1
04.10.2013, 11:18 8
Цитата Сообщение от Mawrat Посмотреть сообщение
нарушит единообразие в архитектуре приложения (или группы приложений). Именно в этом я вижу основную причину "нетехнологичности".
Напомню, мы говорим исключительно о R/O доступе. Нарушить ничего не удастся в принципе.

И, кроме того, речь идет о частной задаче - выгрузке .DBF в Oracle, а не о гетерогенном комплексе, где нужно поддержать целостность распределенной базы. С тем же успехом (но с большими усилиями) можно выгрузить данные из .DBF в текст, например, и импортировать штатными средствами Oracle. Можно не писать никакого отдельного клиента, а использовать OCI. И еще куча вариантов.

IMHO, ранее предложенный - лучший.
0
13105 / 5886 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
04.10.2013, 11:48 9
Цитата Сообщение от gazlan Посмотреть сообщение
Напомню, мы говорим исключительно о R/O доступе. Нарушить ничего не удастся в принципе.
И, кроме того, речь идет о частной задаче - выгрузке .DBF в Oracle, а не о гетерогенном комплексе, где нужно поддержать целостность распределенной базы.
Я не имел в виду вопросы целостности БД. Это другой вопрос. Я про идейную часть говорил. В общем, смысл в том, что murderer показал оптимальное решение конкретной задачи. А я предложил рассмотреть вопрос о месте данной задачи в комплексе, где вопросы единообразия действий могут приобретать особую значимость.
Цитата Сообщение от gazlan Посмотреть сообщение
С тем же успехом (но с большими усилиями) можно выгрузить данные из .DBF в текст, например, и импортировать штатными средствами Oracle. Можно не писать никакого отдельного клиента, а использовать OCI. И еще куча вариантов.
Вот именно, что куча вариантов. При корпоративной разработке архитектор проекта чаще всего ограничивает набор допустимых вариантов - вплоть до единственного. И чтобы отклониться от "генеральной линии", нужно предоставить веские основания.
1
3176 / 1935 / 312
Регистрация: 27.08.2010
Сообщений: 5,131
Записей в блоге: 1
04.10.2013, 12:15 10
Цитата Сообщение от Mawrat Посмотреть сообщение
При корпоративной разработке архитектор проекта чаще всего ограничивает набор допустимых вариантов - вплоть до единственного. И чтобы отклониться от "генеральной линии", нужно предоставить веские основания.
Разумеется. Полностью согласен с вами.
0
3 / 0 / 0
Регистрация: 06.06.2012
Сообщений: 16
04.10.2013, 17:08  [ТС] 11
Цитата Сообщение от Mawrat Посмотреть сообщение
Здесь лучше использовать компоненты, специально предназначенные для работы с БД. Например, можно использовать TADOQuery. На форму надо положить 2 TADOQuery - ADOQuery1 и ADOQuery2. ADOQuery1 связать с DBF файлом, ADOQuery2 - связать с таблицей Oracle. ADOQuery1 в режиме просмотра - Browse (это предустановленный режим). Для ADOQuery2 установить свойство: CashedUpdates := True.
Обработка будет заключаться в следующем. Открываем ADOQuery1. В цикле делаем следующее. ADOQuery2 переводим в режим Insert (ADOQuery2.Insert), читаем записи из ADOQuery1 и записываем их в ADOQuery2. Через каждые, скажем, 500 обработанных записей, выполняем запись в целевую базу через вызов ADOQuery2.ApplyUpdates(0). Затем, опять переводим ADOQuery2 в режим вставки ADOQuery2.Insert. Записываем в ADOQuery2 следующие 500 записей и записываем их в БД - ADOQuery2.ApplyUpdates(0). И т. д., до момента, когда будут записаны все записи, взятые из ADOQuery1.

Для настройки ADOQuery1 и ADOQuery2, следует сформировать для них строки соединения - ConnectionString. Шаблоны ConnectionString для DBF и Oracle можно взять отсюда: http://www.connectionstrings.com: DBF / FoxPro, Oracle.
Вот я так и сделал только провайдер у меня: Provider=MSDASQL.1;Persist Security Info=False;Data Source=dBASE Files;

т.к. других нет.

Теперь проблема с кодировкой. Выводит: €??®*®¬*?© ®????.

Пробую использовать OemToAnsi - не получается. Как побороть ?
BDE устанавливать не предлагать. AsAnsiString тоже пробовал.
0
4172 / 1822 / 218
Регистрация: 06.10.2010
Сообщений: 4,093
04.10.2013, 17:18 12
Смотри "Табл. 9. Идентификаторы кодовой страницы файла" по ссылке. MultiByteToWideChar должна помочь.
0
3 / 0 / 0
Регистрация: 06.06.2012
Сообщений: 16
04.10.2013, 17:22  [ТС] 13
Цитата Сообщение от murderer Посмотреть сообщение
Смотри "Табл. 9. Идентификаторы кодовой страницы файла" по ссылке. MultiByteToWideChar должна помочь.
Что сделать то нужно ? По второй ссылке вообще на с++ улетел.
0
13105 / 5886 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
04.10.2013, 20:49 14
Цитата Сообщение от SAMatyunin Посмотреть сообщение
Теперь проблема с кодировкой. Выводит: €??®*®¬*?© ®????.
Пробую использовать OemToAnsi - не получается. Как побороть ?
Похоже на UTF-8. Если надо преобразовать к Ansi строке:
Delphi
1
2
3
4
5
6
7
8
var
  S : AnsiString; //В Delphi 2007 и более ранних версиях String = AnsiString.
...
begin
...
  S := Utf8ToAnsi(...);
  MessageBox(S);
end;
1
3 / 0 / 0
Регистрация: 06.06.2012
Сообщений: 16
07.10.2013, 12:59  [ТС] 15
Цитата Сообщение от Mawrat Посмотреть сообщение
Похоже на UTF-8. Если надо преобразовать к Ansi строке:
Delphi
1
2
3
4
5
6
7
8
var
  S : AnsiString; //В Delphi 2007 и более ранних версиях String = AnsiString.
...
begin
...
  S := Utf8ToAnsi(...);
  MessageBox(S);
end;
Нет, не подошло.
0
13105 / 5886 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
07.10.2013, 14:16 16
SAMatyunin, тогда как выше murderer предложил - надо проверить, какая кодовая страница указана в самом DBF файле.
Делается так (согласно описанию структуры):
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var
  F : File;
  B : Byte;
  Od : TOpenDialog;
begin
  //Диалог выбора файла.
  Od := OpenDialog1; //OpenDialog1 уже должен быть на форме.
  if Od.InitialDir = '' then
    Od.InitialDir := ExtractFilePath( ParamStr(0) );
  if not Od.Execute then Exit;
  if not FileExists(Od.FileName) then begin
    MessageBox(0, 'Файл с заданным именем не найден. Действие отменено.'
      ,'Файл не найден!', MB_YESNO + MB_ICONWARNING + MB_APPLMODAL);
  end;
  
  AssignFile(F, Od.FileName);
  Reset(F, 1); //Открываем файл с наименьшим блоком доступа в 1 байт.
  try
    Seek(F, $1D); //Переходим к байту со смещением $1D.
    BlockRead(F, B, SizeOf(B));
  finally
    CloseFile(F);
  end;
  ShowMessage('ID кодовой страницы: ' + IntToStr(B));
end;
Теперь, по полученному ID в табл. 9. Идентификаторы кодовой страницы файла надо найти описание - какая кодовая страница используется.

Добавлено через 31 минуту
И ещё идентификатор языкового драйвера можно прочитать. Табл.10. Идентификаторы языковых драйверов в dBASE 7.
Чтение ID кодовой страницы и ID языкового драйвера:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var
  F : File;
  IdCp : Byte;
  IdLangDrv : AnsiString;
  Od : TOpenDialog;
begin
  //Диалог выбора файла.
  Od := OpenDialog1; //OpenDialog1 уже должен быть на форме.
  if Od.InitialDir = '' then
    Od.InitialDir := ExtractFilePath( ParamStr(0) );
  if not Od.Execute then Exit;
  if not FileExists(Od.FileName) then begin
    MessageBox(0, 'Файл с заданным именем не найден. Действие отменено.'
      ,'Файл не найден!', MB_YESNO + MB_ICONWARNING + MB_APPLMODAL);
  end;
  
  AssignFile(F, Od.FileName);
  Reset(F, 1); //Открываем файл с наименьшим блоком доступа в 1 байт.
  try
    //ID кодовой страницы.
    Seek(F, $1D); //Переходим к байту со смещением $1D.
    BlockRead(F, IdCp, SizeOf(B));
    //ID языкового драйвера.
    SetLength(IdLangDrv, 32);
    Seek(F, $20);
    BlockRead(F, IdLangDrv[1], Length(IdLangDrv));
  finally
    CloseFile(F);
  end;
  ShowMessage('ID кодовой страницы: ' + IntToStr(IdCp)
    + #13#10'ID языкового драйвера: ' + IdLangDrv);
end;
Зная эти ID, уже можно будет предположить, как выполнить перекодировку.
1
3 / 0 / 0
Регистрация: 06.06.2012
Сообщений: 16
07.10.2013, 14:49  [ТС] 17
Выбрал свой файл, с указанным кодом. В итоге:
ID кодовой страницы: 0
ID языкового драйвера: LEVEL
0
13105 / 5886 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
07.10.2013, 15:03 18
Да, уж. Тогда предлагаю так сделать. Надо какую-нибудь строку, прочитанную из этой БД, без преобразований, как есть, записать в файл диске и выложить этот файл здесь. Я его по-изучаю.

Записать строку в файл можно так:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const
  Fn = 'StrData.txt';
var
  F : File;
  S : AnsiString;
  FileName : String;
begin
...
  FileName := ExtractFilePath(ParamStr(0)) + Fn;
  //Если версия Delphi выше, чем 2007, то так: S := ADOQuery1.Fields[x].AsAnsiString;
  S := ADOQuery1.Fields[x].AsString;
  AssignFile(F, FileName);
  Rewrite(F, 1);
  try
    BlockWrite(F, S[1], Length(S));
  finally
    CloseFile(F);
  end;
  ShowMessage('Данные записаны в файл:'#13#10 + FileName);
end;
SAMatyunin, а какая версия Delphi используется?
0
3176 / 1935 / 312
Регистрация: 27.08.2010
Сообщений: 5,131
Записей в блоге: 1
07.10.2013, 15:09 19
Цитата Сообщение от Mawrat Посмотреть сообщение
тогда как выше murderer предложил - надо проверить, какая кодовая страница указана в самом DBF файле
Угу. Приложите сам DBF-файл.
Что поменьше и не содержит секретов :-)
1
13105 / 5886 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
07.10.2013, 15:24 20
Цитата Сообщение от gazlan Посмотреть сообщение
Угу. Приложите сам DBF-файл.
Что поменьше и не содержит секретов :-)
Хорошо бы.
SAMatyunin, если информация секретная, то хотя бы первые 68 байт из этого файла посмотреть бы. Или с запасом, на всякий случай - 100 байт.
Как записать первые 100 байт из DBF в другой файл на диске:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const
  Fn = 'HeadData.dat';
var
  F : File;
  S : AnsiString;
  DBName, FileName : String;
  Len : Integer;
  Od : TOpenDialog;
begin
  //Диалог выбора DBF файла.
  Od := OpenDialog1; //OpenDialog1 уже должен быть на форме.
  if Od.InitialDir = '' then
    Od.InitialDir := ExtractFilePath( ParamStr(0) );
  if not Od.Execute then Exit;
  if not FileExists(Od.FileName) then begin
    MessageBox(0, 'Файл с заданным именем не найден. Действие отменено.'
      ,'Файл не найден!', MB_YESNO + MB_ICONWARNING + MB_APPLMODAL);
  end;
  DBName := Od.FileName;
  
  //Имя файла, в который мы сохраним данные. Он будет расположен в той же папке,
  //где лежит исполняемый файл программы.
  FileName := ExtractFilePath(ParamStr(0)) + Fn;
  
  AssignFile(F, DBName);
  Reset(F, 1);
  SetLength(S, 100);
  try
    BlockRead(F, S[1], Length(S), Len);
  finally
    FileClose(F);
  end;
  SetLength(S, Len);
 
  AssignFile(F, FileName);
  Rewrite(F, 1);
  try
    BlockWrite(F, S[1], Length(S));
  finally
    FileClose(F);
  end;
 
  ShowMessage('Данные записаны в файл:'#13#10 + FileName);
end;
1
07.10.2013, 15:24
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
07.10.2013, 15:24
Помогаю со студенческими работами здесь

Импорт .dbf в PostgreSQL. C#
Здравствуйте. Возникла задача импорта dbf файла в базу данных Postgre... нашла всего несколько...

Импорт из Excel в dbf
Как на VBA сделать импорт (выборочных) данных в DBF ? Нравится как это реализовано в 1с. Хотелось...

Импорт из dbf файла
имеется dbf файл reg.dbf, из него необходимо извлечь данные и поместить в таблицу sql думаю...

Импорт из *.dbf в Регистр сведений
Пытаюсь написать код для импорта данных из *.dbf файла в регистр сведений &НаКлиенте Процедура...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru