يقوم QFile بحفظ الملفات عند إنهاء البرنامج، ولن يحفظ ملفات بحجم 500 ميجابايت تقريبًا على الإطلاق

StackOverflow https://stackoverflow.com//questions/22002095

سؤال

نعم يا رفاق، هذا أنا مرة أخرى.لدي الكود التالي:

void MainWindow::on_startButton_clicked()
{
  QNetworkAccessManager *nam = new QNetworkAccessManager(this);
  QNetworkReply *re = nam->get(QNetworkRequest(QUrl("http://somesite/ai/iai.jpg")));
  QEventLoop loop;
  QObject::connect(reply, SIGNAL(readyRead()), &loop, SLOT(quit()));
  loop.exec();
  ui->dbgOut->insertHtml("<font color='green'>OK</font><br>");
  ui->dbgOut->insertHtml("##################################");
  //save
  QFile file("C:\\a.bin");
  file.open(QIODevice::WriteOnly);
  file.write(re->readAll());
  file.close();
}

وعندي مشكلتين:

  1. عندما أنقر على الزر، يقوم بتنزيل الملفات ولكنه لن يكتبها على القرص الصلب.يمكنني الانتظار لمدة 5 أو 10 دقائق ولا شيء.في هذا الوقت، يتم تخزين الملف بأكمله داخل ذاكرة البرنامج.إذا قمت بإغلاق برنامجي، يتم حفظها على القرص.

  2. لا يتم حفظ الملفات الكبيرة (~500 ميجابايت) على الإطلاق.عندما أقوم بإغلاق البرنامج، فإنه يتعطل على الفور.

كيف يمكنني تعديله بحيث يقوم برنامجي بحفظ الملفات التي تم تنزيلها "في الوقت الفعلي"؟

هل كانت مفيدة؟

المحلول

عدم التفاعل هو بسبب re->readAll() على جهاز بحجم غير معروف عبارة عن مكالمة محظورة.وسوف تستمر في القراءة حتى الانتهاء من الطلب.

تتعلق مشكلة الملفات الكبيرة بزيادة مصفوفة البايت التي تحتوي على الملف.في مرحلة ما، سيكون حجم مصفوفة البايت الخاصة بك، على سبيل المثال، 400 ميجابايت، وبعد ذلك يجب أن تنمو لتبلغ ضعف هذا الحجم، لذلك سيتعين عليك الاحتفاظ بحوالي 1 جيجابايت مرة واحدة، في قطعتين كبيرتين، وبسبب تجزئة مساحة العنوان سوف يفشل طلب التخصيص ويتعطل برنامجك.

تؤدي التغييرات الصغيرة في التعليمات البرمجية الخاصة بك إلى السلوك المطلوب:تبدأ بالقراءة والكتابة في وقت واحد، فقط قم بالربط بين الاثنين:

class MainWindow {
  ...
  // You shouldn't be creating a new network access manager for each request.
  QScopedPointer<QNetworkAccessManager> m_nam;
  ...
};

void MainWindow::handleError(const QNetworkReply *) { ... }
void MainWindow::handleError(const QFile *) { ... }
void MainWindow::on_startButton_clicked()
{
  // Lazily create the network access manager once.
  if (!m_nam) m_nam.reset(new QNetworkAccessManager);
  // The file is destructed, and thus flushed and closed, when the
  // last shared pointer to this file is destructed.
  QSharedPointer<QFile> output(new QFile("C:\\a.bin"));
  if (!output->open(QIODevice::WriteOnly)) return;
  QNetworkReply *reply = m_nam->get(QNetworkRequest(QUrl("http://somesite/ai/iai.jpg")));
  // The lambda syntax creates a functor object that holds a copy
  // of the reply pointer and the output file pointer.
  // This functor will be destructed when the reply is destructed.
  QObject::connect(reply, &QIODevice::readyRead, [this, output, reply]{
    QByteArray data(reply->bytesAvailable(), Qt::Uninitialized);
    qint64 in = reply->read(data.data(), data.size());
    qint64 out = output->write(in);
    if (in < 0) {
      handleError(reply); 
      reply->deleteLater();
    }
    else if (out != in) {
      handleError(output.data());
      reply->deleteLater();
    }
  });
  // The reply will self-destruct when finished, thus deleting the file
  // instance.
  QObject::connect(reply, &QNetworkReply::finished, reply, &QObject::deleteLater);
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top