2014-02-25 85 views
1

是的,這是我的一次。我有下面的代碼:QFile在程序退出時保存文件,根本不會保存〜500MB文件

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. 根本沒有保存大文件(〜500MB)。當我關閉程序時,它立即崩潰。

如何編輯它,以便我的程序能夠「實時」保存下載的文件?

+0

1)你應該連接到結束(),而不是readyRead()。對於內存優化,您可以通過chunk讀取塊,但使用鏈接readyRead。 2)請出示墜機的追蹤。 – lpapp

+0

[用Qt下載文件?](http://stackoverflow.com/questions/13747548/downloading-a-file-with-qt) –

回答

4

非交互性是因爲具有未知大小的設備上的re->readAll()是阻塞調用。它將繼續閱讀直到請求完成。

大文件的問題與增加保存文件的字節數組有關。在某些情況下,你的字節數組將會是400MB,然後它將不得不增長到2倍的大小,所以你必須一次保存大約1GB,分兩塊,由於地址空間碎片化,分配請求將失敗,您的程序崩潰。

小的變化對您的代碼產生預期的行爲:在你開始閱讀和書寫一次,而且只是鏈接二:

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); 
}