08.06.2006, 16:38 | #21 |
Участник
|
Эххх, вот если б вы еще и готовые классы выкладывали ;(
Или хотя бы первые три места по скорости этого забега |
|
08.06.2006, 19:13 | #22 |
Moderator
|
Цитата:
Сообщение от Recoilme
Попробуйте так:
PHP код:
Рассмотрим, однако, что происходит при таком подходе. Допустим у нас есть код номенклатуры ItemId = "000333" (строка - 6 символов). При выгрузке в файл запишется 7 символов: '000333 Для упрощения анализа создадим вручную текстовый файл с единственной строкой: '000333 (7 символов), cохраним его под именем test000333.xls и откроем его Excel-ем: 1. В открывшемся Excel в ячейке А1 так и отображается '000333 т.е. с ведущим апострофом. 2. Введем в соседнюю ячейку B1 формулу: =ДЛСТР(А1) . Результат = 7 (символов) 3. Введем далее в ячейку C1 формулу: =А1 & A1 . Результат = '000333'000333 4. Еще раз посмотрим, что мы имеем к этому времени: - в ячейке А1 отображается: '000333 - в ячейке B1 отображается: 7 - в ячейке C1 отображается: '000333'000333 5. Войдём в режим редактирования ячейки А1, нажав на ней клавишу F2. И сразу выйдем, нажав Enter. 6. Посмотрим что получилось теперь: - в ячейке А1 отображается: 000333 - в ячейке B1 отображается: 6 - в ячейке C1 отображается: 000333000333 (т.е. мы наконец достигли в ячейке А1 такой ситуации, которая складывается, когда пользователь вводит последовательность символов '000333 в самом Excel, а не грузит ее из текстового файла с расширением xls) Выгрузка из Аксапты у Job70, конечно, очень быстрая... Но вы думаете, пользователь будет счастлив от такого, пусть даже очень быстро полученного, результата? |
|
09.06.2006, 09:31 | #23 |
злыдень
|
Насчет счастья не уверен, но мы работаем в таком формате несколько лет с поставщиками (B2B), в частности референсы товаров выгружаются с ведущим апострофом. Это, насколько мне известно, штатный способ задания типа текстового поля в эксель. Что Вы и продемонстрировали нажав F2 - эксель удалил ведущий апостроф. Если Вам известны другие способы принудительного форматирования ячеек - было бы интересно узнать о них.
__________________
Ибо зло есть лучшая сила человека. "Человек должен становиться все лучше и злее" -- так учу я. /Ф. Ницше/ |
|
09.06.2006, 10:04 | #24 |
Участник
|
Цитата:
Сообщение от Gustav
НО! Текстовое поле ItemId становится числовым с откусыванием ведущих нулей ("00333" -> 333). Можно исправить ситуацию, например, каким-нибудь тегом?
2. выгрузите в XML и сравните Будет что-то типа: Код: <Style ss:ID="s21"> <NumberFormat ss:Format="@"/> </Style> ... <Cell ss:StyleID="s21"><Data ss:Type="String">00001</Data></Cell> test&data выгрудалось как test&data а то XL может не понять |
|
09.06.2006, 10:20 | #25 |
Moderator
|
Цитата:
Сообщение от Recoilme
Что Вы и продемонстрировали нажав F2 - эксель удалил ведущий апостроф.
Если Вам известны другие способы принудительного форматирования ячеек - было бы интересно узнать о них. "Другие способы принудительного форматирования" - это контролируемо выводить данные в родную таблицу Excel, а не в текстовый файл, который потом неконтролируемо открывается. В xml-способе AndyD-а в этой ветке ведущие нули сохраняются. Сохраняются они и в моем 2-м джобе в теме Поговорим об ADO . Здесь есть, правда, другая крайность: если пользователь зайдет в такую ячейку и просто нажмет Enter, то ведущие нули пропадут и строка "000333" превратится в число 333. Но это можно победить, если по окончании собственно вывода форматировать кодом такие проблеменые колонки как текст (т.е. всё по-прежнему под контролем). К небольшому сожалению, xml-способ AndyD-а работает только начиная с версии Excel 2002 (XP), но, с другой стороны, мы же должны смотреть вперед, а не только постоянно оглядываться назад... |
|
09.06.2006, 10:26 | #26 |
Moderator
|
Цитата:
Сообщение от belugin
1. поменяйте формат ячейки на текстовый
|
|
09.06.2006, 11:00 | #27 |
Участник
|
2 belugin
Насчет & и т.п. Excel нормально отрабатывает их присутствие в данных, единственно - если угловые скобки идут парой <> - то будет ошибка формата. Но вообще согласен - надо отрабатывать такие ситуации. Вот код функции, заменяющей спецсимволы в строке X++: str 1 entity[5]; str 6 entityReference[5]; str getEntities(str s1) { int j, pos; ; for (j=1;j<=5;j++) { pos = strscan(s1, entity[j], 1, strlen(s1)); while (pos) { s1 = substr(s1, 1, pos-1) + entityReference[j] + substr(s1, pos+1, strlen(s1)); pos = strscan(s1, entity[j], pos + 1, strlen(s1)); } } return s1; } ; entity[1] = "&"; entity[2] = "<"; entity[3] = ">"; entity[4] = "'"; entity[5] = '"'; entityReference[1] = "&"; entityReference[2] = "<"; entityReference[3] = ">"; entityReference[4] = "'"; entityReference[5] = """; .... buf += strfmt( ... ledgerTrans.RecId, getEntities(ledgerTrans.AccountNum), getEntities(ledgerTable.AccountName), ledgerTable.AccountPlType, ledgerTrans.BondBatchTrans_RU, ledgerTrans.BondBatch_RU, date2str(ledgerTrans.TransDate, 321, 2, 3, 2, 3, 4), getEntities(ledgerTrans.Txt), strltrim(strrem(num2str(ledgerTrans.AmountMST, 10, 2, 1, 0), "+")), ledgerTrans.Crediting, #toFile ? "" : (cnt mod 2 == 1 ? " ss:StyleID=\"s15\"" : " ss:StyleID=\"s16\""), cnt mod 2 == 1 ? " ss:StyleID=\"s12\"" : " ss:StyleID=\"s13\"", cnt mod 2 == 1 ? " ss:StyleID=\"s10\"" : " ss:StyleID=\"s11\"", #toFile ? (cnt mod 2 == 1 ? " ss:StyleID=\"s15\"" : " ss:StyleID=\"s16\"") : ""); ... PS упс. исправил
__________________
Axapta v.3.0 sp5 kr2 Последний раз редактировалось AndyD; 09.06.2006 в 11:43. |
|
13.06.2006, 12:12 | #28 |
Moderator
|
Коллеги, на самом деле, наш фестиваль-"мундиаль" различных способов экспорта Axapta => Excel продолжается. Приглашаю вас к активному участию.
Хотелось бы увидеть данные по CSV, DDE, Clipboard+PasteSpecial и др. Экспортеры всех видов, присоединяйтесь! P.S. (пока идёт чемпионат мира по футболу, слово "мундиаль" считается приличным ) |
|
13.06.2006, 19:19 | #29 |
Moderator
|
Ну, я сам немножко поковырялся... не с целью бития рекордов, а как раз наоборот – с целью небольшой разборки, направленной на выяснения некоторого предела низкой скорости - типа "медленнее которой остается только способ вписывания значений в ячейки Excel шариковой ручкой"
Абстрагируемся на некоторое время от точности получаемых результатов (я имею в виду, в частности, потенциальные проблемы с пресловутыми ведущими нулями в текстовых значениях, состоящих из цифр, а также потерю точности в длинных цифровых текстовых кодах, например, в 20-тизначных банковских счетах, где возможно обнуление последних 5 разрядов) и сосредоточимся исключительно на скорости вывода (пусть пока текст "000333" пишется в ячейку Excel как число 333, а дата "13.06.06" как число 38881 - просто тупо посмотрим на длительность всего процесса в целом). Способы, представленные AndyD и Recoilme, демонстрируют высокую скорость выгрузки. Задался вопросом: а как поведет себя на тестовом задании популярный класс ComExcelDocument_RU? Примерно представлял, что "фигово" (о низкой скорости уже "слышал" на Форуме). Но захотелось оценить меру "фиговости", поэтому обо всём по порядку. Этот класс в своем первозданном виде (слой DIS) предоставляет нам в распоряжение 2 своих метода, которые можно использовать для решения нашей тестовой задачи: 1. метод static str numToNameCell(int _iCol, int _iRow) - например, для получения текстового адреса ячейки "B1" по номеру строки = 1 и по номеру столбца = 2 2. метод public void insertValue(BookMark _bookMark, anyType _anyVal, int _workSheet = 1) - для записи значения в эту ячейку "B1". Набросал тестовый джоб следующего вида: X++: static void SpeedTest_Job1(Args _args) { LedgerTrans ledgerTrans; LedgerTable ledgerTable; ComExcelDocument_RU excel; int row; int timeFullStart, timeFullFinish, timeFullTotal; ; timeFullStart = timenow(); excel = new ComExcelDocument_RU(); excel.newFile("", true, -1); row = 0; while select ledgerTrans join ledgerTable where ledgerTrans.AccountNum == ledgerTable.AccountNum { row++; if (row > 50000) break; excel.insertValue(ComExcelDocument_RU::numToNameCell( 1, row), ledgerTrans.RecId); excel.insertValue(ComExcelDocument_RU::numToNameCell( 2, row), ledgerTrans.AccountNum); excel.insertValue(ComExcelDocument_RU::numToNameCell( 3, row), ledgerTable.AccountName); excel.insertValue(ComExcelDocument_RU::numToNameCell( 4, row), strfmt('%1', ledgerTable.AccountPlType)); excel.insertValue(ComExcelDocument_RU::numToNameCell( 5, row), ledgerTrans.BondBatchTrans_RU); excel.insertValue(ComExcelDocument_RU::numToNameCell( 6, row), ledgerTrans.BondBatch_RU); excel.insertValue(ComExcelDocument_RU::numToNameCell( 7, row), ledgerTrans.TransDate); excel.insertValue(ComExcelDocument_RU::numToNameCell( 8, row), ledgerTrans.Txt); excel.insertValue(ComExcelDocument_RU::numToNameCell( 9, row), ledgerTrans.AmountMST); excel.insertValue(ComExcelDocument_RU::numToNameCell(10, row), strfmt('%1', ledgerTrans.Crediting)); } timeFullFinish = timenow(); timeFullTotal = timeFullFinish - timeFullStart; info('Время выполнения, сек'); info(int2str(timeFullTotal)); } Время выполнения джоба - 3615 сек, т.е. практически ровно 1 час. Для сравнения: время выполнения на этом же компе джобов AndyD и Recoilme - 29 сек и 12 сек соответственно. Решил заглянуть внутрь этих двух методов класса ComExcelDocument_RU. Заглянул. Расстроился… Есть ощущение, что адресация к ячейкам воплощалась по принципу "Что вижу в Excel - о том пою. Как вручную работаю - так и запрограммирую. Вижу ячейки в первой строке Excel - A1, B1, C1... но, однако, смекаю, что вывод на лист, скорее всего, будет производиться в двух циклах: внешний - по строкам, тут всё в порядке: 1, 2, 3, 4, 5... и внутренний - по столбцам - здесь неудобство: порядок чисел-номеров колонок 1, 2, 3, 4, 5... нужно превращать в буквы А, B, C, D, E... С одной целью - чтобы потом сцепить букву столбца и цифру строки и выйти на какой-нибудь Range("A1"), и дальше через метод insertValue задать значение свойства Value2". Возникает вопрос: А ЗА-ЧЕМ так, мягко говоря, сложно? Со времен версии Excel 5 (1994 год) - первой версии Excel, когда вместо специфического макроязыка версии 4 пришёл Visual Basic - так вот, со времен версии 5 в Excel присутствует способ адресации к ячейкам листа при помощи метода Cells(номер строки, номер столбца), предназначенный как раз для нужд циклического перебора ячеек. Для обращения к прямоугольным диапазонам ячеек используется формат Range(Cells(1-я строка диапазона, 1-й столбец диап-на), Cells(посл. Строка диап-на, посл.столбец диап-на)) - а не только адресация вида Range("A1:H150"), как это пишет макрорекордер на VBA в Excel. Существуют другие полезные методы адресации, например, Offset... Набросал второй тестовый джоб: X++: static void SpeedTest_Job2(Args _args) { LedgerTrans ledgerTrans; LedgerTable ledgerTable; ComExcelDocument_RU excel; COM doc; COM actSheet; COM cells; int row; int timeFullStart, timeFullFinish, timeFullTotal; ; timeFullStart = timenow(); excel = new ComExcelDocument_RU(); excel.newFile("", true, -1); doc = excel.getComDocument(); actSheet = doc.ActiveSheet(); cells = actSheet.Cells(); row = 0; while select ledgerTrans join ledgerTable where ledgerTrans.AccountNum == ledgerTable.AccountNum { row++; if (row > 50000) break; COM::createFromVariant( cells.Item(row, 1) ).Value2( ledgerTrans.RecId ); COM::createFromVariant( cells.Item(row, 2) ).Value2( ledgerTrans.AccountNum ); COM::createFromVariant( cells.Item(row, 3) ).Value2( ledgerTable.AccountName ); COM::createFromVariant( cells.Item(row, 4) ).Value2( strfmt('%1', ledgerTable.AccountPlType) ); COM::createFromVariant( cells.Item(row, 5) ).Value2( ledgerTrans.BondBatchTrans_RU ); COM::createFromVariant( cells.Item(row, 6) ).Value2( ledgerTrans.BondBatch_RU ); COM::createFromVariant( cells.Item(row, 7) ).Value2( ledgerTrans.TransDate ); COM::createFromVariant( cells.Item(row, 8) ).Value2( ledgerTrans.Txt ); COM::createFromVariant( cells.Item(row, 9) ).Value2( ledgerTrans.AmountMST ); COM::createFromVariant( cells.Item(row, 10) ).Value2( strfmt('%1', ledgerTrans.Crediting) ); } timeFullFinish = timenow(); timeFullTotal = timeFullFinish - timeFullStart; info('Время выполнения, сек'); info(int2str(timeFullTotal)); } Опытные коллеги наверняка знают обо всем об этом. Обидно за новичков, которые приходят в Аксу, сталкиваются с ComExcelDocument_RU как с неким "стандартом де-факто" и первое время вынуждены идти по этому, как мне кажется, не совсем верному пути... Теряя это самое драгоценное время! |
|
|
За это сообщение автора поблагодарили: mazzy (5), DreamCreator (3), JeS (1), Silphidae (1). |
13.06.2006, 22:59 | #30 |
Administrator
|
2Gustav: Читаю - прям как энциклопедию .... классно. Здорово получилось. (Пока еще раз одобрить не могу) Если выкрою время (в чем сомневаюсь, но можно постараться) - то надо будет еще 2 механизма проверить - через OWC и буфер обмена.
__________________
Возможно сделать все. Вопрос времени |
|
14.06.2006, 10:45 | #31 |
Участник
|
Еще один вариант - при помощи DDE.
Время выгрузки - 20-21 с PS Так как пользователь может в настройках отключить возможность обработки запросов DDE, то, перед созданием класса clientDDE, можно вставить сброс этого флага X++: app.IgnoreRemoteRequests(false); ddeClient = new DDEClient("Excel", sheet.Name()); Заодно добавил выгрузку ч/з буфер обмена. Для выгрузки использую TextBuffer.toClipboart(). Для переключения используется макрос DDE. Значение TRUE - выгрузка ч/з DDE, значение FALSE - clipboard Время выгрузки примерно одинаковое для обоих вариантов X++: static void ExportExcelDDE(Args _args) { LedgerTrans ledgerTrans; LedgerTable ledgerTable; int timeFullStart, timeFullFinish, timeFullTotal; int cnt = 0; str Buf, s; ComExcelDocument_Ru excel; COM doc; COM app; COM sheet; COM range; DDEClient ddeClient; TextBuffer tb; #define.RowsCount(5000) #define.DDE(false) #define.xlR1C1(0xFFFFEFCA) #if.DDE(false) void LoadKeyboardLayout() { dll dll = new dll("user32"); dllFunction dllFunction = new dllFunction(dll, "LoadKeyboardLayoutA"); #define.KLF_ACTIVATE(1) ; dllFunction.arg(ExtTypes::String, ExtTypes::DWord); dllFunction.returns(ExtTypes::DWord); dllFunction.call("00000419", #KLF_ACTIVATE); } #endif ; // засекаем время timeFullStart = timenow(); excel = new ComExcelDocument_Ru(); excel.newFile("", false); doc = excel.getComDocument(); app = doc.application(); sheet = app.ActiveSheet(); buf = "RecId\tAccountNum\tAccountName\tAccountPlType\tBondBatchTrans_RU\tBondBatch_RU\tTransDate\tTxt\tAmountMST\tCrediting\n"; range = sheet.range("A:A;E:E"); range.NumberFormat("0"); range = sheet.range("B:D;F:F;H:H;J:J"); range.NumberFormat("@"); range = sheet.range("G:G"); range.NumberFormat("ДД.ММ.ГГГГ"); range = sheet.range("I:I"); range.NumberFormat("# ##0,00"); #IF.DDE(true) app.IgnoreRemoteRequests(false); ddeClient = new DDEClient("Excel", sheet.Name()); #ENDIF #IF.DDE(false) tb = new textBuffer(); LoadKeyboardLayout(); #ENDIF cnt++; while select ledgerTrans join ledgerTable where ledgerTrans.AccountNum == ledgerTable.AccountNum && ledgerTrans.TransDate >= str2date('dd.mm.yy',123) && ledgerTrans.TransDate <= str2date('DD.MM.YY',123) { // 10 полей buf += strfmt( "%1\t%2\t%3\t%4\t%5\t%6\t%7\t%8\t%9\t%10\n", ledgerTrans.RecId, ledgerTrans.AccountNum, ledgerTable.AccountName, ledgerTable.AccountPlType, ledgerTrans.BondBatchTrans_RU, ledgerTrans.BondBatch_RU, date2str(ledgerTrans.TransDate, 321, 2, 3, 2, 3, 4), ledgerTrans.Txt, strltrim(strrem(num2str(ledgerTrans.AmountMST, 10, 2, 2, 0), "+")), ledgerTrans.Crediting); cnt++; if (cnt > 0 && (cnt mod #RowsCount == 0)) { s = strfmt("A%1:J%2", cnt-#RowsCount+1, cnt); range = sheet.range(s); #IF.DDE(true) ddeClient.poke(range.Address(true, true, #xlR1C1), buf); #ENDIF #IF.DDE(false) tb.setText(buf); tb.toClipboard(); sheet.paste(range); #ENDIF buf = ""; } if (cnt >= 65000) break; } if (cnt < #RowsCount) range = sheet.range("A1:J" + int2str(cnt)); else range = sheet.range(strfmt("A%1:J%2", cnt-(cnt mod #RowsCount)+1, cnt)); #IF.DDE(true) ddeClient.poke(range.Address(true, true, #xlR1C1), buf); #ENDIF #IF.DDE(false) tb.setText(buf); tb.toClipboard(); sheet.paste(range); #ENDIF excel.visible(true); timeFullFinish = timenow(); timeFullTotal = timeFullFinish - timeFullStart; info('Время выполнения, сек'); info(int2str(timeFullTotal)); }
__________________
Axapta v.3.0 sp5 kr2 Последний раз редактировалось AndyD; 14.06.2006 в 14:39. |
|
|
За это сообщение автора поблагодарили: konopello (1), Gustav (2), JuniorAx (1). |
14.06.2006, 11:42 | #32 |
Moderator
|
Цитата:
Сообщение от sukhanchik
2Gustav: Читаю - прям как энциклопедию .... классно. Здорово получилось. (Пока еще раз одобрить не могу) Если выкрою время (в чем сомневаюсь, но можно постараться) - то надо будет еще 2 механизма проверить - через OWC и буфер обмена.
Цитата:
Сообщение от AndyD
Еще один вариант - при помощи DDE.
Время выгрузки - 20-21 с Код: #define.RowsCount(105000) .......................... if (cnt > 0 && (cnt mod #RowsCount == 0)) .......................... if (cnt >= 65000) break; Код: .......................... && ledgerTrans.TransDate >= str2date('dd.mm.yy',123) && ledgerTrans.TransDate <= str2date('DD.MM.YY',123) .......................... P.S. AndyD, и лучше бы, мне кажется, выложить джоб в окно, а не во вложение. Он небольшой, а просматривать и обсуждать будет значительно удобнее. Последний раз редактировалось Gustav; 14.06.2006 в 11:45. |
|
14.06.2006, 11:59 | #33 |
Участник
|
По поводу RowsCount - это для экспериментов: можно запихнуть в Excel все одним запросом, а можно порциями. Это и регулируется параметром RowsCount (вставлял порциями по 5'000 и добавил впереди 10 для загрузки целиком ). Время в общем-то в пределах погрешности, в отличие от варианта с XML - там это тоже используется
TransDate - это оставил из вашего предложения в самом начале топика. На самом деле ограничиваю по RecId
__________________
Axapta v.3.0 sp5 kr2 |
|
14.06.2006, 13:09 | #34 |
Moderator
|
Цитата:
Сообщение от AndyD
По поводу RowsCount - это для экспериментов: можно запихнуть в Excel все одним запросом, а можно порциями. Это и регулируется параметром RowsCount (вставлял порциями по 5'000 и добавил впереди 10 для загрузки целиком ). Время в общем-то в пределах погрешности, в отличие от варианта с XML - там это тоже используется
Код: DDE Clipboard -------------------------------------------------------- при #define.RowsCount( 1) - 160 сек - 167 сек при #define.RowsCount( 2) - 96 сек - 109 сек при #define.RowsCount( 5) - 54 сек - 50 сек при #define.RowsCount( 10) - 38 сек - 36 сек при #define.RowsCount( 50) - 24 сек - 24 сек при #define.RowsCount( 100) - 22 сек - 22 сек при #define.RowsCount( 1000) - 20 сек - 20 сек при #define.RowsCount( 5000) - 19 сек - 20 сек при #define.RowsCount(10000) - 20 сек - 19 сек при #define.RowsCount(15000) - 19 сек - 19 сек при #define.RowsCount(20000) - 20 сек - 19 сек при #define.RowsCount(25000) - error - 19 сек при #define.RowsCount(50000) - error - 20 сек -------------------------------------------------------- error = свалился с ошибкой "DDE: A request for a synchronous poke transaction has timed out." P.S. Пора рисовать графики в логарифмической шкале P.P.S. добавил в эту же таблицу результаты по варианту "Clipboard" в ответ на: Цитата:
Сообщение от AndyD
Добавил вариант с Clipboard (точнее - один из вариантов, с помощью TextBuffer.toClipboard()).
V Последний раз редактировалось Gustav; 14.06.2006 в 20:11. |
|
14.06.2006, 14:41 | #35 |
Участник
|
Добавил вариант с Clipboard (точнее - один из вариантов, с помощью TextBuffer.toClipboard()). Код в сообщении выше.
__________________
Axapta v.3.0 sp5 kr2 |
|
14.06.2006, 17:12 | #36 |
Moderator
|
Цитата:
Сообщение от AndyD
void LoadKeyboardLayout()
{ dll dll = new dll("user32"); dllFunction dllFunction = new dllFunction(dll, "LoadKeyboardLayoutA"); #define.KLF_ACTIVATE(1) ; dllFunction.arg(ExtTypes::String, ExtTypes:: DWord); dllFunction.returns(ExtTypes:: DWord); dllFunction.call("00000419", #KLF_ACTIVATE); } Это метод что делает? Для чего? Заранее благодарю за ответ. |
|
14.06.2006, 17:56 | #37 |
Участник
|
Активирует русскую раскладку клавиатуры. Если с помощью toClipboard() копировать при активной английской в WIN2000+, то произойдет ошибка конвертации и вместо русских букв будут крякозяблы. Этот эффект можно наблюдать при копировании из Axapta'ы кириллицы (код Recoilme в этом же топике).
На самом деле есть несколько путей решения этой проблемы - копировать в UNICODE, при вставке в Excel указывать тип вставляемых данных (при помощи метода PasteSpecial на WorkSheet).
__________________
Axapta v.3.0 sp5 kr2 |
|
14.06.2006, 22:23 | #38 |
Участник
|
Несколько предложений по исследованию Gustav различных вариантов использования ComExcelDocument_RU
1. При создании нового файла Excel использован код X++: excel.newFile("", true, -1); Первый (самый простой) вариант - открывать в невидимом режиме и показывать после выгрузки всех данных. Второй вариант - запретить перед экспортом пользовательский ввод и обновления в открытой книге. X++: COM app; ; ... app = doc.Application(); app.Interactive(False); // запрет пользовательского ввода app.ScreenUpdating(False); // запрет обновления окна при изменении данных ... app.Interactive(True); app.ScreenUpdating(True); X++: COM doc;
COM actSheet;
COM range;
...
doc = excel.getComDocument();
actSheet = doc.ActiveSheet();
...
while ()
{
...
range = actSheet.range(ComExcelDocument_RU::numToNameCell( 1, row));
range.Value2(ledgerTrans.RecId);
range = actSheet.range(ComExcelDocument_RU::numToNameCell( 2, row));
range.Value2(ledgerTrans.AccountNum);
... 3. Окончательная реабилитация Range. Третий вариант с использованием только интерфейсов - вставка при помощи массивов X++: COM actSheet; COM range; Array arr; ... while () { ... arr = new Array(Types::String); arr.value( 1, strfmt("%1", ledgerTrans.RecId)); arr.value( 2, strfmt("%1", ledgerTrans.AccountNum)); arr.value( 3, strfmt("%1", ledgerTable.AccountName)); arr.value( 4, strfmt("%1", ledgerTable.AccountPlType)); arr.value( 5, strfmt("%1", ledgerTrans.BondBatchTrans_RU)); arr.value( 6, strfmt("%1", ledgerTrans.BondBatch_RU)); arr.value( 7, strfmt("%1", ledgerTrans.TransDate)); arr.value( 8, strfmt("%1", ledgerTrans.Txt)); arr.value( 9, strfmt("%1", ledgerTrans.AmountMST)); arr.value(10, strfmt("%1", ledgerTrans.Crediting)); range = actSheet.range(strfmt("A%1:J%1", row)); range.value2(COMVariant::createFromArray(arr)); PS. Упс. Ошибка. Так делать нельзя. X++: excel.insertValue(range, ledgerTrans.AccountNum); X++: excel.insertValueInRange(range, ledgerTrans.AccountNum); X++: range.Value2(ledgerTrans.AccountNum);
__________________
Axapta v.3.0 sp5 kr2 Последний раз редактировалось AndyD; 15.06.2006 в 09:24. |
|
|
За это сообщение автора поблагодарили: belugin (11). |
14.06.2006, 23:08 | #39 |
Moderator
|
Цитата:
Сообщение от AndyD
Замечание по поводу второго параметра _bVisible=true - при массовой вставке данных в лист Excel будет довольно ощутимое замедление выгрузки. Еще одна особенность при таком параметре - если пользователь в листе Excel во время вызгрузи выделит ячейку мышкой, то выполнение прервется с ошибкой.
P.S. Собственно говоря, Range-то я и не хаял. Я хаял "заднепроходность" излишнего преобразования номеров строки и колонки в текстовый адрес только для того, чтобы воспользоваться синтаксисом Range("A1") вместо того, чтобы без лишних телодвижений сразу применить что-то вроде Range.Item(1,1) Последний раз редактировалось Gustav; 14.06.2006 в 23:32. |
|
15.06.2006, 17:53 | #40 |
Moderator
|
Цитата:
Сообщение от AndyD
Значительное увеличение времени в первом варианте присходит из-за реализации метода findRange(), используемого в insertValue(). Если заменить этот код на более простой (часть кода взята из второго варианта)
Код: COM doc; COM actSheet; COM range; ... doc = excel.getComDocument(); actSheet = doc.ActiveSheet(); ... while () { ... range = actSheet.range(ComExcelDocument_RU::numToNameCell( 1, row)); range.Value2(ledgerTrans.RecId); range = actSheet.range(ComExcelDocument_RU::numToNameCell( 2, row)); range.Value2(ledgerTrans.AccountNum); ... Итак, что мы имеем? Выяснено: 1. Первый способ - джоб SpeedTest_Job1, основанный на использовании методов ComExcelDocument_RU, медленнее, чем SpeedTest_Job2, основанный на COM, примерно в 3 раза. 2. Причиной трёхкратного замедления являются методы класса ComExcelDocument_RU: - InsertValue (записывает значение в ячейку), - numToNameCell (вычисляет текстовый адрес ячейки). То, что "загрузка хотя и будет происходить медленнее второго способа, но разница будет составлять уже проценты, не разы", просто говорит о том, что метод InsertValue (с findRange внутри), пардон, "гадит" на характеристики процесса гораздо больше, чем метод numToNameCell. На мой взгляд, использование этого комбинированного варианта Код: COM range; ......... range = actSheet.range(ComExcelDocument_RU::numToNameCell( 1, row)); range.Value2(ledgerTrans.RecId); Но использование Value2 в чистом виде - это уже не совсем класс ComExcelDocument_RU. Тогда зачем нам оставлять в алгоритме numToNameCell? Сказав "А", скажем и "Б": Код: COM cells; ......... COM::createFromVariant( cells.Item(row, 1) ).Value2( ledgerTrans.RecId ); |
|
Теги |
benchmark, download, excel, faq, xml, законченный пример, производительность, экспорт/импорт |
|
|