Форум программистов, компьютерный форум, киберфорум
C/C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.78/121: Рейтинг темы: голосов - 121, средняя оценка - 4.78
Эксперт 1С
 Аватар для OverDozero
921 / 326 / 130
Регистрация: 07.04.2011
Сообщений: 1,731

Импорт диапазона из Excel в вариантный массив

05.05.2015, 21:20. Показов 25240. Ответов 34
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем доброго времени суток.Ребята,подскажите пожалуйста,как из Екселя выдернуть сразу диапазон ячеек со значениями и запихнуть в вариантный массив?3 дня уже курю гугл - и все никак не выйдет.В какую сторону хоть копать?
Могу создать вариантный массив,считать каждую ячейку в экселе отдельно,и запихнуть в данный массив.Но при объеме данных свыше 50 000 строк чтение довольно долго выходит.А эти данные еще и обработать надо.
ПЫ.СЫ.Готовый код не прошу - просто пните в нужном направлении наброском кода.Что и куда копать.
Спасибо!
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
05.05.2015, 21:20
Ответы с готовыми решениями:

Как сделать вариантный импорт рисунков?
Разрешите у Вас спросить такую вещь: мне следует сделать следующее. Пользователь выбирает в выпадающем списке одно из двух значений. ...

Как лучше записать вариантный массив в текстовой (.txt) файл
Имеется массив A:variant MyArray := VarArrayCreate(, VarDouble); Как писать тоже знаю, примерно так : var f:textFile; //...

Чтение данных из диапазона (Excel) в массив (Delphi)
Прочитав пару статей на тему быстрой обработки данных excel в delphi, решил считывать данные диапазоном, нежели из каждой ячейки. Но не...

34
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
20.03.2019, 19:29
Студворк — интернет-сервис помощи студентам
Данные находятся в екселе, заносятся в массив arr, их оттуда благополучно можно извлечь по номеру элемента, как Вы и показали в примере чуть выше, но результат работы вот этой строки всегда неверные или я что то не верно делаю:

C++
1
2
3
HRESULT hresult;
long iUBound;
hresult=SafeArrayGetUBound(arr.parray, 1, &iUBound); // статус hresult = S_OK
Но в iUBound записывается всегда значение 1, хотя нижняя граница массива больше одного и по номеру элемента оттуда можно достать данные.
Но при той же абсолютно записи SafeArrayGetLBound - число столбцов массива отображается верно.
Не знаю что не так.
0
Модератор
 Аватар для vxg
3406 / 2177 / 354
Регистрация: 13.01.2012
Сообщений: 8,444
20.03.2019, 19:36
Optimus11, судя по коду вы запрашиваете верхнюю границу первого измерения много мерного массива

Добавлено через 1 минуту
Optimus11, покажите скрин экселя и назовите какие значения вам кажется должна вернуть функция

Добавлено через 25 секунд
... и какие она реально возвращает
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
20.03.2019, 21:26
Да скриншот с экрана екселя не нужен в принципе.
Вот 'nb строчки кода берут диапазон из екселя:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
...
IDispatch *pXlRange;
    {
                VARIANT parm;
        parm.vt = VT_BSTR
        parm.bstrVal = ::SysAllocString(L"A1:D10"); // Данные из этого диапазона заносятся в arr;
 
        VARIANT result;
        VariantInit(&result);
        AutoWrap_1(DISPATCH_PROPERTYGET, &result, pXlSheet, (LPOLESTR)L"Range", 1, parm);
        VariantClear(&parm);
        pXlRange = result.pdispVal;
    }
И соответственно:

long iUBound;
SafeArrayGetUBound(arr.parray, 2, &iUBound); // И соответственно iUBound получается равным = 1

long lUBound;
SafeArrayGetLBound(arr.parray, 2, &lUBound);/ И соответственно lUBound получается равным = 4, соответствует ширине диапазона.

Вот как то так получается.
0
Модератор
 Аватар для vxg
3406 / 2177 / 354
Регистрация: 13.01.2012
Сообщений: 8,444
22.03.2019, 07:59
Optimus11, иии... какие вам значения не нравятся?
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
22.03.2019, 08:44
Вот это SafeArrayGetUBound(arr.parray, 2, &iUBound), где iUBound=1

Я понимаю, что я чего то не понимаю, но хотелось бы получить номер нижней границы массива по вертикали, но немогу реально понять как.
0
Модератор
 Аватар для vxg
3406 / 2177 / 354
Регистрация: 13.01.2012
Сообщений: 8,444
23.03.2019, 16:19
Optimus11, я вас не понимаю. вот есть код
C++
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
        VARIANT addr;
        VARIANT range;
        VARIANT value;
 
        VariantInit(&addr);
        VariantInit(&range);
        VariantInit(&value);
 
        while (true) {
 
        addr.vt = VT_BSTR;
        addr.bstrVal = SysAllocString(L"B3:D6");
        BREAK_ON_FAIL(AutoWrap(DISPATCH_PROPERTYGET, &range, xls.ws.pdispVal, L"Range", 1, addr))
        BREAK_ON_FAIL(AutoWrap(DISPATCH_PROPERTYGET, &value, range.pdispVal, L"Value", 0))
 
        std::cout << V_VT(&value) << std::endl;
 
        SAFEARRAY *sa = V_ARRAY(&value);
 
        long i_min, i_max;
        SafeArrayGetLBound(sa, 1, &i_min);
        SafeArrayGetUBound(sa, 1, &i_max);
 
        std::cout << "i_min = " << i_min << std::endl;
        std::cout << "i_max = " << i_max << std::endl;
 
        long j_min, j_max;
        SafeArrayGetLBound(sa, 2, &j_min);
        SafeArrayGetUBound(sa, 2, &j_max);
 
        std::cout << "j_min = " << j_min << std::endl;
        std::cout << "j_max = " << j_max << std::endl;
 
        break;}
 
        VariantClear(&addr);
        VariantClear(&range);
        VariantClear(&value);
он выводит вот это
8204
i_min = 1
i_max = 4
j_min = 1
j_max = 3
это верно - в value находится VARIANT с типом 8204 - это VT_ARRAY | VT_VARIANT поэтому можно без страха оперировать с ним как с SAFEARRAY - у первого измерения границы (1, 4), у второго (1, 3) - это верно так как диапазон B3 : D6 содержит 4 строки и три столбца. или вы думаете что диапазон должен показать вам в качестве нижней и верхней границ номера строк / столбцов ? не должен. это не его дело.
1
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
23.03.2019, 23:09
думаете что диапазон должен показать вам в качестве нижней и верхней границ номера строк / столбцов ? не должен. это не его дело.
Спасибо, именно так я ошибочно и думал.
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
24.03.2019, 19:36
А может быть можете пожалуйста подсказать в чем разница между:

1)
C++
1
2
3
4
VT_I4   4-byte signed integer value.
VT_I8   8-byte signed integer.
и
VT_R8   64-bit IEEE floating point value.
То есть получается так, что когда я читаю данные из ексель и в ячейке ексель находится екселевской числовое значение, то когда пробегаюсь по элеменнтам массива куда были записанные данные из екселя, то в элеменете Variant срабатывает:
C++
1
2
3
if (V_VT(&arr_element) == VT_R8)
{
}
VT_I4 и VT_I8 - не срабатывает.

Но, когда создается variant массив и туда записываются данные для последующей записи в екель:
C++
1
2
3
4
5
6
7
8
9
10
11
for (int i = 1; i <= 15; i++) {
        for (int j = 1; j <= 15; j++) {
 
            VARIANT tmp;
            tmp.vt = VT_I4; 
            tmp.lVal = i * j;
 
            long indices[] = { i,j };
            SafeArrayPutElement(arr_write.parray, indices, (void *)&tmp);
        }
    }
То в variant массив записываются данные с типом VT_I4 и далее в ексель они записываются корректно, можно в массив добавить и тип VT_R8, но тогда в ексель записывается какие то совершенно другие числа.
Не пойму почему так.

2) И если можно такой вопрос: правильно ли я понимаю, что разница между VT_R8 и VT_R4 - только в разрядности виндовса ? То есть если у меня виндовс 64-разр., то условие:
C++
1
2
3
if (V_VT(&arr_element) == VT_R4)
{
}
Не сработает ? А в 32ух разр., не сработает соответственно VT_R8 ?
0
Модератор
 Аватар для vxg
3406 / 2177 / 354
Регистрация: 13.01.2012
Сообщений: 8,444
24.03.2019, 20:35
Optimus11, 1) в ячейках excel хранится VARIANT и он сам там по идее преобразует все куда надо если надо - если пишите R8 то и запишет R8 если конечно вы его в какое надо поле положите, обратно выдаёт наверное унифицированный тип - или строка или плавающая точка 2) нет, разрядности не имеет к этому отношения, R8 это C++ double, R4 это C++ float
1
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
30.03.2019, 20:03
Я сдаюсь, пытаюсь теперь записать данные в екель, берут тот же микрософтовский пример, он конечно же работает, но записывает в ексель числа VT_I4, а мне нужно чтобы записывался тектовый формат, то есть BSTR, вот кусочек работающего кода:

C++
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
...
// Create a 15x15 safearray of variants...
    VARIANT arr_write;
    arr_write.vt = VT_ARRAY | VT_VARIANT;
    {
        SAFEARRAYBOUND sab[2];
        sab[0].lLbound = 1; sab[0].cElements = 15;  
        sab[1].lLbound = 1; sab[1].cElements = 15; 
        arr_write.parray = SafeArrayCreate(VT_VARIANT, 2, sab);
    }
 
VARIANT tmp; 
tmp.vt = VT_BSTR;
 
string string_value = "001";
 
// Fill safearray with some values...  /// 
    for (int i = 1; i <= 15; i++) {
        for (int j = 1; 15; j++) {
 
tmp.bstrVal = ::SysAllocString(_com_util::ConvertStringToBSTR(string_value.c_str())); //Преобразование string в bstr
 
long indices[] = { i,j };
 
SafeArrayPutElement(arr_write.parray, indices, (void *)&tmp);
        }
    }
И данные записываются, но записывается, только "1", а не "001", то есть в виде в формате числа, а не текстовом формате.
Причем методом тыка мне как то удалось записать именно в текстовом формате, вроде бы я обьявил массив, как BSTR, что то типа:

C++
1
arr_write.vt = VT_ARRAY | VT_BSTR;
Но потом решил поэксперементировать и забыл, что я сделал (((
0
Модератор
 Аватар для vxg
3406 / 2177 / 354
Регистрация: 13.01.2012
Сообщений: 8,444
31.03.2019, 06:57
Optimus11, ввести цифру как текст даже руками бывает не просто) если это не принципиально - вводите ‘001
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
31.03.2019, 08:09
Бывает же такое, открыл с утра Ваше сообщение и сразу вспомнил, что я делал :
C++
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
// Create a 15x15 safearray of variants...
    VARIANT arr_write;
    arr_write.vt = VT_ARRAY | VT_BSTR;   // Тут объявляется, что VT_Array должен быть VT_BSTR
    {
        SAFEARRAYBOUND sab[2];
        sab[0].lLbound = 1; sab[0].cElements = vector_stroka_for_write.size();  
        sab[1].lLbound = 1; sab[1].cElements = vector_stolbech_for_write.size(); 
        arr_write.parray = SafeArrayCreate(VT_BSTR, 2, sab);   // А тут забыл, так же указать, что ArrayCreate будет VT_BSTR
    }
 
BSTR tmp_bstr;  // объявляем переменную из которой будет заносится данные в arr_write
 
string string_value = "001";
 
for (int i = 1; i <= 15; i++) {
        for (int j = 1; j <= 15; j++) {
 
 
tmp_bstr = _com_util::ConvertStringToBSTR(string_value.c_str());
 
///////// 
//VARIANT tmp; 
//tmp.bstrVal; // через tmp.bstrval - не работает, ошибок нет, но в екcель ничего не вносится.
/////////
 
    long indices[] = { i,j };
 
    SafeArrayPutElement(arr_write.parray, indices, tmp_bstr);
}
 }
 
AutoWrap_write(DISPATCH_PROPERTYPUT, NULL, pXlRange, (LPOLESTR)L"Value", 1, arr_write);
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
02.04.2019, 20:40
Позвольте еще один вопрос с участием все той же замечательной autowrap функцией:

C++
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
Autowrap()
 
int main()
{
CoInitialize(NULL);
CLSID clsid;
 
HRESULT hr = CLSIDFromProgID(L"Excel.Application", &clsid); 
 
IUnknown* pUnk;
hr = GetActiveObject(clsid, NULL, &pUnk);
 
IDispatch *pXlApp;
hr = pUnk->QueryInterface(IID_IDispatch, (void**)&pXlApp);
 
IDispatch *pXlSheet;
    {
        VARIANT result;
        VariantInit(&result);
        AutoWrap_get_sheet_name(DISPATCH_PROPERTYGET, &result, pXlApp, (LPOLESTR)L"ActiveSheet", 0);
        pXlSheet = result.pdispVal;
    }
 
VARIANT rngResult;
AutoWrap_get_sheet_name(DISPATCH_PROPERTYGET, &rngResult, pXlSheet, (LPOLESTR)L"Name", 0);
}
Соответсвенно в rngResult получаем имя аквтиного на данный момент листа.
Но, когда я пытаюсь применить тот же код для получения имени рабочей книги, то есть вот так:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
...
 
IDispatch *pXlBooks;
    {
        VARIANT result;
        VariantInit(&result);
        AutoWrap_get_sheet_name(DISPATCH_PROPERTYGET, &result, pXlApp, (LPOLESTR)L"Workbooks", 0);
        pXlBooks = result.pdispVal;
    }
 
 
VARIANT rngResult;
AutoWrap_get_sheet_name(DISPATCH_PROPERTYGET, &rngResult, pXlBooks, (LPOLESTR)L"Name", 0);
Почему ругается на IDispatch::GetIDsOfNames<"Names">faild e/err 0x800200006

То есть получается метод или свойство Name для или Activesheets находится, а для Workbook нет ?

Добавлено через 21 минуту
Все разобрался - ActiveWorkBook!
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
05.04.2019, 19:47
Не могу понять, вот есть предположим 10 открытых файла из которых предположим нужно из ячейки "A1" считать данные.
Понятно, как считать данные из активного на данный момент файла и активного в нем листа, через autowrap:

C++
1
2
3
4
5
6
7
IDispatch *pXlsheet;
    {
        VARIANT result;
        VariantInit(&result);
        AutoWrap_Choose_Active(DISPATCH_PROPERTYGET, &result, pXlApp, (LPOLESTR)L"ActiveSheets", 0);
        pXlsheets = result.pdispVal;
    }
Или из активного файла, но другого листа в нем:
C++
1
2
3
4
5
6
{
        VARIANT result;
        VariantInit(&result);
        AutoWrap_Choose_Active(DISPATCH_PROPERTYGET, &result, pXlApp, (LPOLESTR)L"Worksheets", 1, (LPOLESTR)L"Лист2" );
        pXlsheets = result.pdispVal;
}
и соответсвенно:
C++
1
2
VARIANT rngResult;
AutoWrap(DISPATCH_PROPERTYGET, &rngResult, pXlRange, (LPOLESTR)L"Value", 0);
То есть зная название листов в активном Workbook`ё можно пройтись по ним и считать с них данные, я думал примерно так же можно пройтись и по списку WorkBooks зная имена файлов который открыты:
C++
1
2
3
4
5
6
7
IDispatch *pXlsheet;
    {
        VARIANT result;
        VariantInit(&result);
        AutoWrap_Choose_Active(DISPATCH_PROPERTYGET, &result, pXlApp, (LPOLESTR)L"WorkBooks", 1, (LPOLESTR)L"Files1" );
        pXlsheets = result.pdispVal;
    }
Но так возникает ошибка:
C++
1
IDispatch:Invoke<"WorkBooks"=0000023c> faild w/err 0x80020009
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
07.04.2019, 20:14
Для этого есть метод Activate.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
07.04.2019, 20:14
Помогаю со студенческими работами здесь

Excel: создать новый массив по возрастанию элементов выделенного диапазона рабочей таблицы
Разработать подпрограмму создания нового массива по возрастанию элементов выделенного диапазона рабочей таблицы. Элементы массива задать...

импорт выделенного диапазона
добрый день!у меня есть таблица в Еxcel ee нужно импортировать, но только тот диапазон который был выделен.можете подсказать как это...

Экспорт-импорт данных Excel-Access-Excel
Доброе время суток уважаемые форумчане. Приходит информация в экселевской таблице. Скидываю её в общую базу в Access. Для отчета...

Обработка Excel и импорт из Excel в Access
Прошу совета профессионалов. С Excel-м ранее дел не имел. Задание: файлы Excel из одной папки отредактировать, и сохранить в другой. Из...

Excel -> Access -> Excel, импорт - экспорт
Добрый день! Есть табель учета рабочего времени в таблице Excel, задача - переместить данные со всех листов книги в DB Access, позже...


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

Или воспользуйтесь поиском по форуму:
35
Ответ Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru