2014-02-25 59 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); 
}