Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: считывание таблицы из xls (Excel)
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Общие вопросы
Алексей1153
задача - считать исходные данные из экселевского файла. Имеется три колонки, каждую нужно поместить в свой вектор

по всяким примерам с форума сделал чтение таким образом

QAxObject excel("Excel.Application");
if(!excel.isNull())
{
    if(QAxObject* workbooks=excel.querySubObject("WorkBooks"))
    {
        QString nativeFilePath=QDir::toNativeSeparators(filename);

        if(QAxObject* workbook=workbooks->querySubObject("Open(const QString&)", nativeFilePath))
        {
            if(QAxObject* sheet=workbook->querySubObject("Worksheets(const QVariant&)", 1))
            {
                if(QAxObject* usedRang = sheet->querySubObject("UsedRange"))
                {
                    QAxObject* usedRows = usedRang->querySubObject("Rows"   );
                    QAxObject* usedCols = usedRang->querySubObject("Columns");
                    
                    int intRowStart = usedRang->property("Row"   ).toInt();
                    int intColStart = usedRang->property("Column").toInt();
                    int intRows     = usedRows->property("Count" ).toInt();
                    int intCols     = usedCols->property("Count" ).toInt();

                    ...
                    ...

                    bool bOk=true;
                    for(int col=e_time; col<e_count+intCols; col++)
                    {
                        ...
                        ...

                        for(int row=intRowStart; row<intRowStart+intRows; row++)
                        {
                            if(QAxObject* cell=sheet->querySubObject("Cells(int,int)", row, col ))
                            {
                                double val=cell->dynamicCall("Value()").toDouble(&bOk);

                                ...
                                ...

                                delete cell;
                            }

                            if(!bOk)break;
                        }

                        if(!bOk)break;
                    }
                }
            }
            workbooks->dynamicCall("Close" );
        }
    }

    excel.dynamicCall("Quit");
}


но, блин, так долго вытаскивается даже 1000 значений - капец.

Понимаю, что проблема в том, что я по ячейке добываю.

Может, как-то не по ячейке можно доставать, а сразу колонку ?
lanz
Можно получить объект Range, а потом прочитать его value как QVariantList.

QAxObject *range = sheet->querySubObject("Range(const QVariant&)", "A1:A100");
QVariantList vlist = qvariant_cast<QVariantList> (range->dynamicCall("Value()"));


Если рэнж прямоугольный, получится QVariantList QVariantList-ов.

Не проверял :lol:, у меня была обратная задача, я выкидывал данные через qscript (ax - обертка для генератора объектов, SubObj - вызывает querySubObject, table - список списков).
Раскрывающийся текст
var table = [];
    for (var i = 0; i < exids.length; ++i) {
        var row = make_row(exids[i]);
        table.push (row);                       ;        
    };
    var range_str = ("A2:" + columns[ExportCols.length - 1] + (exids.length + 1));
    range = ax.SubObj(sheet, "Range(QVariant)", range_str);
    range.Value = table;
Алексей1153
lanz, спасибо. Даже работает ) Только я применил вариант с циферными индексами

Range(Cells(1, 1), Cells(100, 3))

Ужасает только количество delete :D Но тут, видимо, никак иначе

Кстати, он возвращает QVariantList of QVariantList, только это набор строк, что не совсем кузяво (но терпимо). Никак его не заставить возвращать набор колонок ?
lanz
Не пробовал. Можно посмотреть в сторону свойства Columns или сделать три Range по одному для каждой колонки.
Алексей1153
оставил так, вроде устраивает
Olga
Добрый вечер!
Стоит задача считать данные из excel файла и добавить их в БД MySql.
В файле содержиться более 30000 строк. Если считываю по ячейки и вставляю в БД, то все это делается ооооооооооооочень медленно.
Может есть более быстрый способ???
lanz
Можно использовать объект Range, как я уже писал тут выше. Он работает значительно быстрее.
Приведите пример как вы делаете, может можно срезать углы где-то.
Pavel12345
Вы уверены, что хорошо знаете эксель? Пройдите курс MS Excel Профессионал от специалистов ведущей международной консалтинговой компании. Вы научитесь работать в экселе в 2 раза быстрее и будете уверены, что решаете каждую задачу наиболее эффективным способом. Внимание! Осталось 3 места, до пятницы скидка 20%. Оставьте заявку по ссылке: http://msexcel.pro?ch=frm
Гость
Здравствуйте.
Похожая задача.
Нужно читать 3 столбца из *.csv файла.
Столбцы читаю (вижу в отладчике значения).
....................
Файл *.h
QVariantList List1;
QVariantList List2;
QVariantList List3;
.............................

Файл *.cpp
......................
QAxObject *range1 = worksheet->querySubObject("Range(const QVariant&)","A1:A16000");
QAxObject *range2 = worksheet->querySubObject("Range(const QVariant&)","B1:B16000");
QAxObject *range3 = worksheet->querySubObject("Range(const QVariant&)","C1:C16000");
List1 = qvariant_cast<QVariantList> (range1->dynamicCall("Value()"));
List2 = qvariant_cast<QVariantList> (range2->dynamicCall("Value()"));
List3 = qvariant_cast<QVariantList> (range3->dynamicCall("Value()"));
.............................................................

А как выделить элемен из списка List1, List2, List3 - не знаю.

Пробовал по разному:
................................................
QVariantList::const_iterator it = List1.constBegin();
int i=1;
while (it != List1.constEnd())
{
myVarName[i].setValue((*it).toString());//QVariant myVarName[16000]

i++;
it++;
}
Не получается.
Нужно преобразов List1 в массив строк, List2 в массив даты времени, List3 в массив значений.
В отладчике вижу тип QString, но даже его не могу засунуть в myVarName.

Спасибо.
lanz
Цитата
Не получается.

Что именно не получается?
Гость
Это моя первая работа с Qt (моя специальность электроник, программировал в MSVC 6 более 10 лет назад).
Есть файл *.csv.
В нем записана информация о работе оборудования (переменная, время, значение переменной).
Данная информация собирается с интервалом в 5 секунд.
Мне нужно построить график для отображения изменения переменной во времени.

Я создал три массива QVariantList List1, List2, List3 и три массива QVariant myVarName[20000], QVariant myDataTime[20000], QVariant myVarValue[20000].
(Количество переменных в массивах QVariant 20000 - это пока для теста, желательно сделать динамический массив в зависимости от количества строк.
Кол-во строк я получаю, а как сделать динамический массив пока точно не знаю.)

Я посмотрел примерыи написал несколько вариантов программы:
1. Сначало читал весь файл - 16000 строк 5 столбцов занимает по времени 12 секунд
...................................
if( fileName.contains(reg) ){
QMessageBox::information(this,"Файл открыт","Все успешно");
QTextStream stream(&mFile);
QString buffer = stream.readAll();
ui->textEdit_3->setText(buffer);
mFile.flush();
mFile.close();
................................
2. Потом читал по ячейкам (это вообще долго):
...................................
for(countRow; countRow < iAllRow; ++countRow){
myVarName[countRow] = worksheet->querySubObject("Cells( int, int)", countRow, 1)->property("Value").toString();
myDataTime[countRow] = worksheet->querySubObject("Cells( int, int)", countRow, 2)->property("Value").toString();
myVarValue[countRow] = worksheet->querySubObject("Cells( int, int)", countRow, 3)->property("Value").toFloat();
}
................................................................................
.....
3. Сейчас остановился на вашем варианте (читает бысто, выжу в отладчике):
QAxObject *range1 = worksheet->querySubObject("Range(const QVariant&)","A1:A16000");
QAxObject *range2 = worksheet->querySubObject("Range(const QVariant&)","B1:B16000");
QAxObject *range3 = worksheet->querySubObject("Range(const QVariant&)","C1:C16000");
List1 = qvariant_cast<QVariantList> (range1->dynamicCall("Value()"));
List2 = qvariant_cast<QVariantList> (range2->dynamicCall("Value()"));
List3 = qvariant_cast<QVariantList> (range3->dynamicCall("Value()"));
................................................................................
..................................
Сейчас мне нужно из списков QVariantList List1, List2, List3 занести значения (типы Sting, DataTime, Float) соответственно в массивы myVarName[], myDataTime[], myVarValue[].
То есть, создаю итератор QList<QVariant>::iterator it = List1.begin();, указывающий на первый элемент списка List1.

А вот как Первый элемент списка занести в первый элемент массива QVariant - не знаю.

Пробовал по разному, не получается.
.................................................................
while (it != List1.end())
{
myVarName[i].setValue((*it).toString());
str1=qvariant_cast<QString>(*it);
ui->textEdit_4->append(str1);

i++;
it++;
}

Как правильно перенести значения из списков QVariantList в массивы QVariant?
lanz
Цитата
myVarName[i].setValue((*it).toString());

Должно работать, выглядит правильно.
EDIT: Возможно что то напутано с объявлением массивов?

Цитата
QString buffer = stream.readAll();
ui->textEdit_3->setText(buffer);

Очень странно что чтение чистого csv занимает больше чем получение тех же данных через COM.
Скорее всего все время естся в методе setText.
Этот способ по идее самый быстрый должен быть.

Цитата
Кол-во строк я получаю, а как сделать динамический массив пока точно не знаю

Используйте QVector например.
Гость
Массивы объявлены:

QVariant myVarName[20000];
QVariant myDataTime[20000];
QVariant myVarValue[20000];


QVariantList List1;
QVariantList List2;
QVariantList List3;
Гость
Я в текстовом поле (Я не наблюдаю значения переменных myVarName[i].
ui->textEdit_2->append(myVarName[i].toString());
Как увидеть значение массивов?
Гость
В отладчика переменная "myVarName[i].setValue((*it).toString());" имеет два значения, но кадое из них "no such vlue"

Как из списка писать в массив QVariant я пока не знаю?

Есть какие нибудь идеи?



pfuser
Здравствуйте, еще раз.
Зарегестрировался.
Вопрос еще открыт.

Проект и тестовый файл прилагаю.
Заранее благодарен.
pfuser
Если напрямую установить значение: myVarName[3].setValue(111), то все читает хорошо.
Значит (*it).toString() указывает не на значение переменной QVariantList

Если использовать it.i->t() - читает QVariantList,
но записать в QVariant не могу: myVarName[i].setValue(it.i->t());



QVariantList::const_iterator it = List1.constBegin();
int i=1;
while (it != List1.constEnd())
{
// j=it.i->t();
myVarName[i].setValue(it.i->t());
i++;
it++;
}

.....да
pfuser
Все правильно, что-то с типа ми объявления.

У меня объявлены массивы:
QVariant myVarName[20000];
QVariant myDataTime[20000];
QVariant myVarValue[20000];

В отладчика myVarName[х] выглядит как QVariant(QVariantList).
Правильно наверное QVariant(не знаю что).
lanz
Фишка в том, что Range() возвращает двумерный массив, т.е. вектор векторов. Доставать как то так
//Считываю список List1
        QAxObject *range1 = worksheet->querySubObject("Range(const QVariant&)",QString("A1:A%1").arg( iAllRow ) );

//Считываю список List2        
        QAxObject *range2 = worksheet->querySubObject("Range(const QVariant&)",QString("B1:B%1").arg( iAllRow ));


//Считываю список List3        
        QAxObject *range3 = worksheet->querySubObject("Range(const QVariant&)",QString("C1:C%1").arg( iAllRow ));

        List1 = qvariant_cast<QVariantList> (range1->dynamicCall("Value()"));
        List2 = qvariant_cast<QVariantList> (range2->dynamicCall("Value()"));
        List3 = qvariant_cast<QVariantList> (range3->dynamicCall("Value()"));

        QList<QVariant>::iterator it = List1.begin();
        int i=1;
        while (it != List1.end())
        {
            QVariantList lst = it->value<QVariantList>();
            ui->textEdit_2->append( lst.begin()->toString() );
            i++;
            it++;
        }

Используйте List1-3 напрямую, зачем вам копировать данные второй раз?
pfuser
Цитата(lanz @ 17.2.2015, 20:25) *
Используйте List1-3 напрямую, зачем вам копировать данные второй раз?

Спасибо. Сейчас проверю.
Мне пока проще или вернее привычнее работать (думать) с массивами, чем с контейнерами.

Спасибо. Все работает. Все супер)))))))))). Теперь перейду к рисованию))))))))))))

То, что я понял.
1) Создается список переменных типа QVariant (то, что я хотел);
2) Итератор нового списка устанавливается на адрес списка, полученного из Range
QVariantList;
3) Так как размерность каждого члена двух списков одинаковая (QList<QVariant> и QVariantList), то через итератор первого списка получаем значение второй переменной.
Как-то так. Только не понятно, почему через итератор QVariantList (*it).toString не работает, но это уже не важно.

Еще раз БОЛЬШОЕ ЧЕЛОВЕЧЕСКОЕ СПАСИБО!
lanz
Цитата
Только не понятно, почему через итератор QVariantList (*it).toString не работает, но это уже не важно.

А вот это написано в документации :lol:
http://qt-project.org/doc/qt-4.8/qvariant.html#toString
Цитата
Returns the variant as a QString if the variant has type() String, Bool, ByteArray, Char, Date, DateTime, Double, Int, LongLong, StringList, Time, UInt, or ULongLong; otherwise returns an empty string.

Так как тип варианта QVariantList, то он не преобразуется и возвращает пустую строку.
pfuser
Цитата(lanz @ 18.2.2015, 19:58) *
Так как тип варианта QVariantList, то он не преобразуется и возвращает пустую строку.

Что-то понял, а пробразовать в то что нужно только так:
1) lst.begin()->toString()
2) lst.begin()->toInt
3) lst.begin()->toFloat
и т.д.?
lanz
Цитата
Что-то понял, а пробразовать в то что нужно только так:
1) lst.begin()->toString()
2) lst.begin()->toInt
3) lst.begin()->toFloat
и т.д.?

Эта запись эквивалентна
QVariantList::const_iterator it = lst.begin();
it->toString(); // что эквивалентно (*it).toString()

Здесь мы получаем первый элемент списка.
Так как у нас столбец, то в каждой строке ровно один элемент, он же первый.
Вообще по хорошему надо проверять список на пустоту/количество элементов.
pfuser
QList<QVariant> и QVariantList - чем отличаются и ещ ене понял.
В первом случает список элементов QVariant, а во втором нечто похожее, только на что пока не понятно.
lanz
Это одно и то же:
http://qt-project.org/doc/qt-4.8/qvariant....antList-typedef
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.