2014-02-25 10 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. 내가 버튼을 클릭하여 파일을 다운로드하지만, HDD에 기록하지 않을 때. 나는 5 분 10 분을 기다릴 수있다. 이 때 전체 파일은 프로그램 메모리에 저장됩니다. 내 프로그램을 닫으면 디스크에 저장됩니다.

  2. 대용량 파일 (~ 500MB)은 전혀 저장되지 않습니다. 프로그램을 닫으면 즉시 중단됩니다.

내 프로그램이 다운로드 한 파일을 "실시간으로"저장하도록 어떻게 편집 할 수 있습니까?

+0

1) (완료에 연결해야한다),하지 readyRead(). 메모리 최적화를 위해, chunk readyReadRead와 함께 chunk를 읽을 수 있습니다. 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); 
}