|
|
#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 // и что делать дальше?
|
|
|
|
|
#2 |
|
Участник
|
Посмотрите класс ComExcelDocument_RU
|
|
|
|
|
#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;
} |
|
|
|
|
#4 |
|
Участник
|
Цитата:
Если для дела, то куда быстрее, как показала практика, импортировать данные через ADO (скромно так).
|
|
|
|
|
#5 |
|
Участник
|
Цитата:
Сообщение от gl00mie
Зачем, если не секрет? Из спортивного интереса?
Если для дела, то куда быстрее, как показала практика, импортировать данные через ADO (скромно так).2. Иногда, требуется и читать, и писать в один и тот же файл. С ADO не очень понятно про то, как определяется тип данных в столбце (как я понял, по нескольким первым строкам). И если, скажем, среди строк встретится число (строка из одних цифр + формат ячейки = число, пример - каталожные номера), то ADO вернет пустую строку.Вроде бы так, когда параметр IMEX не 1. |
|
|
|
|
#6 |
|
Участник
|
Цитата:
Сообщение от gl00mie
Зачем, если не секрет? Из спортивного интереса?
Если для дела, то куда быстрее, как показала практика, импортировать данные через ADO (скромно так).Правда, для работы с двухмерными массивами SafeArray в Axapta пришлось написать свой COM-класс.
__________________
Axapta v.3.0 sp5 kr2 |
|
|
|
|
#7 |
|
Участник
|
Цитата:
Давайте только для чистоты эксперимента выложим тестовый файл для считывания...Цитата:
Правда, для работы с двухмерными массивами SafeArray в Axapta пришлось написать свой COM-класс.
|
|
|
|
|
#8 |
|
Moderator
|
|
|
|
|
|
#9 |
|
Участник
|
Это я к тому, что на чистой Axapta не получилось работать с такими массивами
__________________
Axapta v.3.0 sp5 kr2 |
|
|
|
|
#10 |
|
Участник
|
Цитата:
Впрочем, это, конечно, не принципиально...
Последний раз редактировалось gl00mie; 10.01.2007 в 18:03. |
|
|
|
|
#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. |
|
|
|
|
#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). | |
|
|
#13 |
|
Участник
|
|
|
|
|
|
#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 |
|
|
|
|
#15 |
|
Участник
|
Тьфу, опять забыл про value2
спасибо
|
|
|
|
|
#16 |
|
Участник
|
Не подскажете, какая библиотека нужна для использования SafeArray
При запучке job`а выдается сообщение: COM-объект класса "AxSafeArray.SafeArray" не удалось создать. Убедитесь, что объект был должным образом зарегистрирован на компьютере "USER". |
|
|
|
|
#17 |
|
Участник
|
Так я, наверное, не выкладывал файл.
Если надо, то он во вложении. Надо будет зарегистрировать его вызовом Код: regsvr32 AxSafeArray.dll"
__________________
Axapta v.3.0 sp5 kr2 Последний раз редактировалось AndyD; 23.10.2008 в 11:29. |
|
|
|
| За это сообщение автора поблагодарили: Stainless (1). | |
|
|
#18 |
|
Участник
|
Появилась ошибка в строчке
X++: ... k = SafeArray.AddArrayCol(v1, var); ... |
|
|
|
|
#19 |
|
Участник
|
Упс.
![]() Прошу прощения, выложил старую версию библиотеки PS А можно попросить удалить вложение в предыдущем письме. Я не могу его отредактироваить PPS Вопрос снимается Я через кабинет удалил.
__________________
Axapta v.3.0 sp5 kr2 Последний раз редактировалось AndyD; 23.10.2008 в 14:01. |
|
|
|
|
#20 |
|
Участник
|
Ошибка все равно сохранилась. Версия обоих файлов 1.0.0.1
|
|
|