Алексей1153
25.3.2013, 11:14
задача - считать исходные данные из экселевского файла. Имеется три колонки, каждую нужно поместить в свой вектор
по всяким примерам с форума сделал чтение таким образом
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 значений - капец.
Понимаю, что проблема в том, что я по ячейке добываю.
Может, как-то не по ячейке можно доставать, а сразу колонку ?
Можно получить объект Range, а потом прочитать его value как QVariantList.
QAxObject *range = sheet->querySubObject("Range(const QVariant&)", "A1:A100");
QVariantList vlist = qvariant_cast<QVariantList> (range->dynamicCall("Value()"));
Если рэнж прямоугольный, получится QVariantList QVariantList-ов.
Не проверял
, у меня была обратная задача, я выкидывал данные через 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
25.3.2013, 13:40
lanz, спасибо. Даже работает ) Только я применил вариант с циферными индексами
Range(Cells(1, 1), Cells(100, 3))
Ужасает только количество delete
Но тут, видимо, никак иначе
Кстати, он возвращает QVariantList of QVariantList, только это набор строк, что не совсем кузяво (но терпимо). Никак его не заставить возвращать набор колонок ?
Не пробовал. Можно посмотреть в сторону свойства Columns или сделать три Range по одному для каждой колонки.
Алексей1153
25.3.2013, 19:43
оставил так, вроде устраивает
Добрый вечер!
Стоит задача считать данные из excel файла и добавить их в БД MySql.
В файле содержиться более 30000 строк. Если считываю по ячейки и вставляю в БД, то все это делается ооооооооооооочень медленно.
Может есть более быстрый способ???
Можно использовать объект Range, как я уже писал тут выше. Он работает значительно быстрее.
Приведите пример как вы делаете, может можно срезать углы где-то.
Pavel12345
9.1.2015, 3:27
Вы уверены, что хорошо знаете эксель? Пройдите курс 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.
Спасибо.
Цитата
Не получается.
Что именно не получается?
Это моя первая работа с 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?
Цитата
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 я пока не знаю?
Есть какие нибудь идеи?
Здравствуйте, еще раз.
Зарегестрировался.
Вопрос еще открыт.
Проект и тестовый файл прилагаю.
Заранее благодарен.
Если напрямую установить значение: 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++;
}
.....да
Все правильно, что-то с типа ми объявления.
У меня объявлены массивы:
QVariant myVarName[20000];
QVariant myDataTime[20000];
QVariant myVarValue[20000];
В отладчика myVarName[х] выглядит как QVariant(QVariantList).
Правильно наверное QVariant(не знаю что).
Фишка в том, что 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 напрямую, зачем вам копировать данные второй раз?
Цитата(lanz @ 17.2.2015, 20:25)
Используйте List1-3 напрямую, зачем вам копировать данные второй раз?
Спасибо. Сейчас проверю.
Мне пока проще или вернее привычнее работать (думать) с массивами, чем с контейнерами.
Спасибо. Все работает. Все супер)))))))))). Теперь перейду к рисованию))))))))))))
То, что я понял.
1) Создается список переменных типа QVariant (то, что я хотел);
2) Итератор нового списка устанавливается на адрес списка, полученного из Range
QVariantList;
3) Так как размерность каждого члена двух списков одинаковая (QList<QVariant> и QVariantList), то через итератор первого списка получаем значение второй переменной.
Как-то так. Только не понятно, почему через итератор QVariantList (*it).toString не работает, но это уже не важно.
Еще раз БОЛЬШОЕ ЧЕЛОВЕЧЕСКОЕ СПАСИБО!
Цитата
Только не понятно, почему через итератор QVariantList (*it).toString не работает, но это уже не важно.
А вот это написано в документации
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, то он не преобразуется и возвращает пустую строку.
Цитата(lanz @ 18.2.2015, 19:58)
Так как тип варианта QVariantList, то он не преобразуется и возвращает пустую строку.
Что-то понял, а пробразовать в то что нужно только так:
1) lst.begin()->toString()
2) lst.begin()->toInt
3) lst.begin()->toFloat
и т.д.?
Цитата
Что-то понял, а пробразовать в то что нужно только так:
1) lst.begin()->toString()
2) lst.begin()->toInt
3) lst.begin()->toFloat
и т.д.?
Эта запись эквивалентна
QVariantList::const_iterator it = lst.begin();
it->toString(); // что эквивалентно (*it).toString()
Здесь мы получаем первый элемент списка.
Так как у нас столбец, то в каждой строке ровно один элемент, он же первый.
Вообще по хорошему надо проверять список на пустоту/количество элементов.
QList<QVariant> и QVariantList - чем отличаются и ещ ене понял.
В первом случает список элементов QVariant, а во втором нечто похожее, только на что пока не понятно.
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.