1

I want to write a little program which compress all files from a directory by using qCompress of QByteArray.

However i want to run the compression on a multithreaded environment by using QtConcurrent. But i have some problems.

Here my code :

FilePool pool(folder,suffix);
QFutureWatcher<QString> watcher;
QProgressDialog progressDialog;


connect(&watcher,SIGNAL(progressRangeChanged(int,int)),&progressDialog,SLOT(setRange(int,int)));

connect(&watcher,SIGNAL(progressValueChanged(int)),&progressDialog,SLOT(setValue(int)));

connect(&progressDialog,SIGNAL(canceled()),&watcher,SLOT(cancel()));

QFuture<QString> future = QtConcurrent::filtered(pool,FindInFile(search));
QString text;

watcher.setFuture(future);

progressDialog.exec();

future.waitForFinished();
//Test for compressing file

QFile outFile("testCompress.ecf");
outFile.open(QIODevice::WriteOnly);
QByteArray nonCompressedData;
foreach(const QString &file,future.results()){
    //Fichier d'entrée
    QFile inFile(file);
    inFile.open(QIODevice::ReadOnly);
    nonCompressedData.append(inFile.readAll());
    inFile.close();
    text += file + "\n";
}

//QByteArray compressedData(qCompress(nonCompressedData,9));
//PROBLEM HERE
QFuture<QByteArray> futureCompressor = QtConcurrent::filtered(nonCompressedData,qCompress);
futureCompressor.waitForFinished();
QByteArray compressedData = futureCompressor.results();

outFile.write(compressedData);

The problem is that the compiler raise me an errors

First : No matching function for call to filtered(&QByteArray,).

Second : converstion from QList to non scalar type QByteArray requested.

So, my question is,is it possible to do what i want?

Thanks in advance

JohnnyBeGoody
  • 253
  • 1
  • 3
  • 15
  • It is certainly possible to compress an array in a separate thread. But the way you try to do it... it smells a bit like 'let us take a random function from QtConcurrent, pass randomly some parameters to it, and hope for the best' – Greenflow Apr 29 '15 at 12:59
  • Then, can you lead me on the best way to do this? – JohnnyBeGoody Apr 29 '15 at 13:17
  • You can write a function, which compresses your QByteArray using qCompress and then execute this function in another thread using QtConcurrent::run. – Greenflow Apr 29 '15 at 13:40
  • OK i understand, and what do you think about creating a vector of QByteArray and use map on it to qCompress? – JohnnyBeGoody Apr 29 '15 at 13:43
  • 1
    QtConcurrent::filtered has a totally different use case. The qCompress is as filter function wrong, it has the wrong signature. And even if QtComcurrent::filtered could accept qCompress, filtered would feed it the QByteArray byte by byte.... qCompress does not take single bytes. – Greenflow Apr 29 '15 at 13:44
  • 1
    QtConcurrent::map + vector of QByteArray is at least the right direction. I don't think you can use qCompress as MapFunctor directly... needs to be **U function(const T &t);**. A lambda function would be elegant to wrap qCompress, I think. – Greenflow Apr 29 '15 at 13:51
  • Oh ok, really thank you for this complete reply ! I understand better now. – JohnnyBeGoody Apr 29 '15 at 14:01
  • Nope. I saw too late that you use qt4. No lambdas there. – Greenflow Apr 30 '15 at 07:54
  • @Greenflow , can you help me for establishing that lambda function to wrap qCompress? I overloaded the operator function which having an uncompressed QByteArray input and returns a qCompressed QByteArray But I don't really understand how the QtConcurrent knows that it needs to use this function. – JohnnyBeGoody Apr 30 '15 at 08:00
  • OK i have the possibility for changing version of QT. – JohnnyBeGoody Apr 30 '15 at 09:24

1 Answers1

1

Not sure, if qt4 can handle this.

QList<QByteArray> list;
...add ByteArrays to list...
auto wordMapFn  = [](QByteArray &arr){arr=qCompress(arr, 9);};
QFuture<void> f = QtConcurrent::map(list,wordMapFn);

This compresses all QByteArrays in list. If you want to keep your uncompressed arrays, use mapped instead of map. wordMapFn has to be adjusted accordingly. If you want to compress only a single QByteArray QtConcurrent::run might be more appropriate.

Pay attention to the life time of list.

Greenflow
  • 3,935
  • 2
  • 17
  • 28
  • Ok, this works perfectly. But now i'ms asking another question. Is it possible to transform this lambda into a class which overload the operator? Because, being new in C++, i don't really understand lambda expressions. – JohnnyBeGoody Apr 30 '15 at 11:46
  • Ok it's done, i found how to write a class instead of a lambda expression. Thank you for your precious help – JohnnyBeGoody Apr 30 '15 at 11:54