comment signaler la progression des données lues sur un fichier QuaGzipFile (bibliothèque QuaZIP)

J’utilise QuaZIP 0.5.1 avec Qt 5.1.1 pour C ++ sur Ubuntu 12.04 x86_64.

Mon programme lit un fichier binary compressé volumineux, généralement 1 Go de données non compressées ou plus, et effectue certains calculs. Il n’est pas très volumineux en termes de calcul et la plupart du temps est passé en entrée / sortie. Donc, si je peux trouver un moyen de rapporter combien de données du fichier sont lues, je peux le rapporter sur une barre de progression et même fournir une estimation de l’ETA.

J’ouvre le fichier avec:

QuaGzipFile gzip(fileName); if (!gzip.open(QIODevice::ReadOnly)) { // report error return; } 

Mais il n’existe aucune fonctionnalité dans QuaGzipFile pour trouver la taille du fichier ni la position actuelle.

Je n’ai pas besoin de trouver la taille et la position du stream non compressé, la taille et la position du stream compressé sont correctes, car une estimation approximative de la progression suffit.

Actuellement, je peux trouver la taille du fichier compressé en utilisant QFile(fileName).size() . De plus, je peux facilement trouver la position actuelle dans un stream non compressé , en conservant la sum des valeurs de retour de gzip.read() . Mais ces deux chiffres ne correspondent pas.

Je peux modifier la bibliothèque QuaZIP et accéder à des ressources internes liées à zlib, si cela peut vous aider.

Il n’y a pas de moyen fiable pour déterminer la taille totale du stream non compressé. Voir cette réponse pour plus de détails et des solutions de contournement possibles.

Cependant, il existe un moyen d’obtenir une position dans un stream compressé:

 QFile file(fileName); file.open(QFile::ReadOnly); QuaGzipFile gzip; gzip.open(file.handle(), QuaGzipFile::ReadOnly); while(true) { QByteArray buf = gzip.read(1000); //process buf if (buf.isEmpty()) { break; } QFile temp_file_object; temp_file_object.open(file.handle(), QFile::ReadOnly); double progress = 100.0 * temp_file_object.pos() / file.size(); qDebug() << qRound(progress) << "%"; } 

L'idée est d'ouvrir le fichier manuellement et d'utiliser un descripteur de fichier pour obtenir la position. QFile ne peut pas suivre les changements de position externes, donc file.pos() sera toujours temp_file_object à 0. Nous créons donc temp_file_object partir du descripteur de fichier forçant QFile à demander la position du fichier. Je pourrais utiliser une API de niveau inférieur (telle que lseek() ) pour obtenir la position du fichier, mais je pense que mon chemin est plus multi-plateforme.

Notez que cette méthode n’est pas très précise et peut donner des valeurs de progression supérieures à la réalité. En effet, zlib peut lire et décoder en interne plus de données que ce que vous avez déjà lu.

Dans les versions 1.2.4 et supérieures, vous pouvez utiliser la fonction gzoffset() pour obtenir la position actuelle dans le fichier compressé. La version actuelle de zlib est 1.2.8.

En utilisant un hack laid à zlib, j’ai pu trouver une position dans un stream compressé.

Tout d’abord, j’ai copié la définition de gz_stream partir de gzio.c (de la source de zlib-1.2.3.4), jusqu’à la fin de quagzipfile.cpp. Ensuite, j’ai réimplémenté la fonction virtuelle qint64 QIODevice::pos() const :

 qint64 QuaGzipFile::pos() const { gz_stream *s = (gz_stream *)d->gzd; return ftello64(s->file); } 

Puisque quagzipfile.cpp et quagzipfile.h semblent être indépendants des autres fichiers de bibliothèque QuaZIP, il est peut-être préférable de copier la fonctionnalité dont j’ai besoin à partir de ces fichiers et d’éviter ce piratage?

La version actuelle du programme ressemble à ceci:

 QFile infile(fileName); if (!infile.open(QIODevice::ReadOnly)) return; qint64 fileSize = infile.size; infile.close(); QuaGzipFile gzip(fileName); if (!gzip.open(QIODevice::ReadOnly)) return; qint64 nread; char buffer[bufferSize]; while ((nread = gzip.read(&buffer, bufferSize)) > 0) { // use buffer int percent = 100.0 * gzip.pos() / fileSize; // report percent } gzip.close();