08.01.2007, 13:30 | #1 |
Участник
|
Построчный импорт из Excel через COM
Что-то никак не пойму, возможен ли импорт строки целиком из Excel через массив? Типа, операция обратная экспорту с помощью массивов http://www.axforum.info/forums/showt...5729#post35729
Через sysExcelRange не получается вообще никогда, ругается то на многомерность safe array, то на некорректность его же. X++: Array arr; .... sysExcelRange = sysExcelWorksheet.range('A1:E1'); arr = sysExcelRange.value(); // ошибка! X++: COM range, worksheet; COMVariant value; ... range = worksheet.range('A1:E1'); value = range.value(); // тип - VT_SAFEARRAY // и что делать дальше? |
|
08.01.2007, 17:43 | #2 |
Участник
|
Посмотрите класс ComExcelDocument_RU
|
|
08.01.2007, 18:33 | #3 |
Moderator
|
1. Необходимо уточнить, что смотреть можно, начиная с версии Ax 3.0 SP4. Там действительно в этом классе появляются несколько методов, посвященных именно ИМПОРТУ из Excel. В SP3 про импорт еще "ни слова".
2. Не думаю, что методы эти устроят olesh : _comRange.text() (см. ниже) возвращает содержательный "текст" только для диапазона, состоящего из одной ячейки, например, для A1. Для диапазона из нескольких ячеек, например, для A1:E1 вернется НЕ Null только тогда, когда все ячейки диапазона будут иметь одно и то же неНулл-значение. И вернется, конечно же, как видно из кода ниже, только одно значение (никакой не массив). Цитата:
Сообщение от ComExcelDocument_RU (Ax 3.0 SP4)
Код: protected anyType GetValueFromRange(COM _comRange) { //anyType _anyType; str _anyType; _anyType = this.convertVariant2Str(_comRange.text()); return _anyType; } str convertVariant2Str(COMVariant cv) { str retVal; switch (cv.variantType()) { case COMVariantType::VT_BSTR: retVal = cv.bStr(); break; case COMVariantType::VT_R8: retVal = num2str(cv.double(),-1,-1,-1,-1); break; case COMVariantType::VT_DATE: retval = date2str(cv.date(), -1, -1, -1, -1, -1, 4); //Year as 4 digits break; case COMVariantType::VT_EMPTY: retVal = ''; break; default: error("@SYS59922"); throw Exception::Error; } return retVal; } |
|
09.01.2007, 01:30 | #4 |
Участник
|
Цитата:
|
|
09.01.2007, 09:43 | #5 |
Участник
|
Цитата:
Сообщение от gl00mie
Зачем, если не секрет? Из спортивного интереса? Если для дела, то куда быстрее, как показала практика, импортировать данные через ADO (скромно так).
2. Иногда, требуется и читать, и писать в один и тот же файл. С ADO не очень понятно про то, как определяется тип данных в столбце (как я понял, по нескольким первым строкам). И если, скажем, среди строк встретится число (строка из одних цифр + формат ячейки = число, пример - каталожные номера), то ADO вернет пустую строку.Вроде бы так, когда параметр IMEX не 1. |
|
10.01.2007, 10:47 | #6 |
Участник
|
Цитата:
Сообщение от gl00mie
Зачем, если не секрет? Из спортивного интереса? Если для дела, то куда быстрее, как показала практика, импортировать данные через ADO (скромно так).
Правда, для работы с двухмерными массивами SafeArray в Axapta пришлось написать свой COM-класс.
__________________
Axapta v.3.0 sp5 kr2 |
|
10.01.2007, 16:45 | #7 |
Участник
|
Цитата:
Цитата:
Правда, для работы с двухмерными массивами SafeArray в Axapta пришлось написать свой COM-класс.
|
|
10.01.2007, 17:02 | #8 |
Moderator
|
|
|
10.01.2007, 17:37 | #9 |
Участник
|
Это я к тому, что на чистой Axapta не получилось работать с такими массивами
__________________
Axapta v.3.0 sp5 kr2 |
|
10.01.2007, 18:01 | #10 |
Участник
|
У AndyD уже, видимо, есть и файл, и код для чтения данных, и даже контрольное время считывания. Хотелось бы, если данные не шибко секретные, тренироваться именно на них Впрочем, это, конечно, не принципиально...
Последний раз редактировалось gl00mie; 10.01.2007 в 18:03. |
|
10.01.2007, 22:41 | #11 |
Участник
|
Вот код загрузки/выгрузки в Excel - 10 колонок * 50 т. строк
X++: { ComExcelDocument_RU excel = new ComExcelDocument_RU(); Com doc; Com app; Com sheet; Com range; COMVariant var; ComVariant v, v1; Array arr; Container c; int i, j, k; Com SafeArray = new Com ("AxSafeArray.SafeArray"); int rowCount; int colCount; int tm = winapi::getTickCount(); ; v = ComVariant::createNoValue(); v1 = new ComVariant(ComVariantInOut::In, ComVariantType::VT_VARIANT); v1.variant(v); arr = new Array(Types::Class); for (j=1;j<=10;j++) { for (i=1;i<=50000;i++) switch (j mod ((i mod 3)+1)) { case 0: arr.value(i, ComVariant::createFromStr(strfmt("??? %1", i))); break; case 1: arr.value(i, ComVariant::createFromInt(i)); break; case 2: arr.value(i, ComVariant::createFromReal(i)); break; } var = ComVariant::createFromArray(arr); k = SafeArray.AddArrayCol(v1, var); } var = v; excel.newFile("", false); doc = excel.getComDocument(); app = doc.Application(); sheet = app.activeSheet(); range = sheet.range("A1:J50000"); c += [strfmt("%1", winapi::getTickCount()-tm)]; range.value2(var); c += [strfmt("%1", winapi::getTickCount()-tm)]; var = range.value2(); rowCount = SafeArray.GetArrayRowCount(var); colCount = SafeArray.GetArrayColCount(var); c += [strfmt("%1", winapi::getTickCount()-tm)]; for (j=1;j<=colCount;j++) { v1 = SafeArray.GetArrayCol(var, j); arr = v1.safeArray(); for (i=1;i<=rowCount;i++) v = arr.value(i); } excel.visible(true); c += [strfmt("%1", winapi::getTickCount()-tm)]; for (i=1;i<=conlen(c);i++) info(conpeek(c, i)); } PS М-да. Попробовал на другой машине. Общее время - 38 сек. Время загрузки в Excel 23 сек. Дохлый у меня комп дома
__________________
Axapta v.3.0 sp5 kr2 Последний раз редактировалось AndyD; 11.01.2007 в 08:32. |
|
11.01.2007, 13:02 | #12 |
Участник
|
А, в принципе, можно обойтись и средаствами Axapta, если считывать по одной строке или колонке.
X++: { ComExcelDocument_RU excel = new ComExcelDocument_RU(); Com doc; Com app; Com sheet; Com range; Array arr; int j; COMVariant v; Array GetArrayFromVariant(COMVariant var) { Binary bin = new Binary(100); int dims; Array ret = null; int cols, rows; int lBound; int i; int locks; ; if (var && var.variantType() == COMVariantType::VT_SAFEARRAY) { bin.attach(var.int(), 24); dims = bin.word(0); if (dims == 2) { bin.attach(var.int(), 16 + dims * 8); cols = bin.dWord(16); rows = bin.dWord(24); if (rows == 1) { locks = bin.dWord(8); if (locks == 0) { bin.dWord(8, locks+1); bin.word(0, 1); try { ret = var.safeArray(); bin.word(0, dims); bin.dWord(8, locks); } catch { bin.word(0, dims); bin.dWord(8, locks); } } } else if (cols == 1) { locks = bin.dWord(8); if (locks == 0) { bin.dWord(8, locks+1); lBound = bin.dWord(20); bin.dWord(16, rows); bin.dWord(20, bin.dWord(28)); bin.word(0, 1); try { ret = var.safeArray(); bin.word(0, dims); bin.dWord(16, cols); bin.dWord(20, lBound); bin.dWord(8, locks); } catch { bin.word(0, dims); bin.dWord(16, cols); bin.dWord(20, lBound); bin.dWord(8, locks); } } } } else if (dims == 1) ret = var.safeArray(); } return ret; } ; excel.open("Имя файла Excel для загрузки.xls",true); doc = excel.getComDocument(); app = doc.Application(); sheet = app.activeSheet(); range = sheet.range("D1:D100"); arr = GetArrayFromVariant(range.value2()); if (arr) { for (j=1;j<=arr.lastIndex();j++) { v = arr.value(j); switch (v.variantType()) { case COMVariantType::VT_BSTR: info(v.bStr()); break; case COMVariantType::VT_INT: info(strfmt("%1", v.int())); break; case COMVariantType::VT_R8: info(strfmt("%1", v.double())); break; } } } }
__________________
Axapta v.3.0 sp5 kr2 Последний раз редактировалось AndyD; 11.01.2007 в 13:12. |
|
|
За это сообщение автора поблагодарили: olesh (1), belugin (14), alex55 (2). |
11.01.2007, 13:51 | #13 |
Участник
|
|
|
11.01.2007, 14:55 | #14 |
Участник
|
Про SAFEARRAY можно посмотреть здесь SAFEARRAY Data Type
С датой/временем можно сделать так 1. Для получения значения из ячеек использовать range.value(10) вместо range.value2() (value2 для даты возвращает число с плавающей точкой) 2. Добавить в обработчик массива X++: case COMVariantType::VT_DATE: info(strfmt("%1 %2", date2str(v.date(), 123, 2, 1, 2, 1, 4), time2str(v.time(), 1, 1))); break;
__________________
Axapta v.3.0 sp5 kr2 |
|
11.01.2007, 15:24 | #15 |
Участник
|
Тьфу, опять забыл про value2 спасибо
|
|
20.10.2008, 17:19 | #16 |
Участник
|
Не подскажете, какая библиотека нужна для использования SafeArray
При запучке job`а выдается сообщение: COM-объект класса "AxSafeArray.SafeArray" не удалось создать. Убедитесь, что объект был должным образом зарегистрирован на компьютере "USER". |
|
20.10.2008, 17:59 | #17 |
Участник
|
Так я, наверное, не выкладывал файл.
Если надо, то он во вложении. Надо будет зарегистрировать его вызовом Код: regsvr32 AxSafeArray.dll"
__________________
Axapta v.3.0 sp5 kr2 Последний раз редактировалось AndyD; 23.10.2008 в 11:29. |
|
|
За это сообщение автора поблагодарили: Stainless (1). |
23.10.2008, 11:08 | #18 |
Участник
|
Появилась ошибка в строчке
X++: ... k = SafeArray.AddArrayCol(v1, var); ... |
|
23.10.2008, 11:26 | #19 |
Участник
|
Упс.
Прошу прощения, выложил старую версию библиотеки PS А можно попросить удалить вложение в предыдущем письме. Я не могу его отредактироваить PPS Вопрос снимается Я через кабинет удалил.
__________________
Axapta v.3.0 sp5 kr2 Последний раз редактировалось AndyD; 23.10.2008 в 14:01. |
|
23.10.2008, 13:15 | #20 |
Участник
|
Ошибка все равно сохранилась. Версия обоих файлов 1.0.0.1
|
|