File downloaden in nur einem Thread

Alles rund um die Programmierung mit Qt
Antworten
Klaue
Beiträge: 13
Registriert: 13. Januar 2006 13:21

File downloaden in nur einem Thread

Beitrag von Klaue »

Hallo zusammen.
Ich habe da so ein kleines Problem.
Ich will eine Datei runterladen. Das funktioniert auch. Da ich aber mehrere Dateien runterladen will, habe ich mir eine Funktion gebastelt, die die Adresse der Datei und den lokalen Dateinamen als Parameter bekommt.
Mein Problem ist nun, dass diese funktion erst zurückkehren sollte, wenn die Datei Fertig runtergeladen ist. So wie ich das aber jetzt habe, wird die Datei in einem neuen Thread runtergeladen während das Hauptprogramm weiterläuft.
Ich könnte jetzt im Hauptprogramm einen while(true)-loop einbauen, der per if einen boolean abfragt und erst, falls dieser true sein sollte, den loop beendet. Den boolean könnte ich per Extrafunktion und dem Signal requestFinished setzen. Ich finde diese "Lösung" aber ziemlich hässlich, ausserdem würde die (soweit ich mich erinnere) den Prozessor ziemlich auslasten, bis die Datei gedownloaded ist.
Ich habe auch schon QTimer in betracht gezogen, aber da das auch nur ein Signal sendet, würde es auf dasselbe rauskommen.
Daher wollte ich fragen, ob hier jemand wüsste, wie ich das besser hinkriegen könnte oder eine alternative Downloadart wüsste.

Die besagte Funktion sieht im Moment so aus:

Code: Alles auswählen

void VCLchecker::downloadFile(string sURL, string sFileName) {
	QString qsURL;
	qsURL = sURL.c_str();
	
	QString fileName;
	fileName = "temp\\";
	fileName += sFileName.c_str();
	
	QUrl url(qsURL);
	
	file = new QFile(fileName);
	if (!file->open(QIODevice::WriteOnly)) {
		QMessageBox::information(this, tr("VCLchecker"), tr("Unable to save the file: %1.").arg(file->errorString()));
		delete file;
		file = 0;
		return;
	}
	
	http->setHost(url.host(), 80);
	httpRequestAborted = false;
	httpGetId = http->get(url.path(), file);
}
Dass die Parameter strings und keine QStrings sind, ist übrigens durchaus gewollt.

Die anderen dazugehörigen Funktionen:

Code: Alles auswählen

void VCLchecker::httpRequestFinished(int requestId, bool error)
{
    if (httpRequestAborted) {
		QMessageBox::information(this, tr("VCLchecker"), tr("Aborted!"));
        if (file) {
            file->close();
            file->remove();
            delete file;
            file = 0;
        }
        return;
    }

    if (requestId != httpGetId) return;
    file->close();

    if (error) {
        file->remove();
        QMessageBox::information(this, tr("VCLchecker"),
                                 tr("Downloading of file failed: %1.")
                                 .arg(http->errorString()));
    }
    delete file;
    file = 0;
    // hier könnte ich eventuell die Membervariable setzen
}

void VCLchecker::readResponseHeader(const QHttpResponseHeader &responseHeader)
{
    if (responseHeader.statusCode() != 200) {
        QMessageBox::information(this, tr("VCLchecker"),
                                 tr("Downloading of file failed (statuscode): %1.")
                                 .arg(responseHeader.reasonPhrase()));
        httpRequestAborted = true;
        http->abort();
        return;
    }
}
Die connects sehen so aus (falls das wichtig wäre):

Code: Alles auswählen

connect(http, SIGNAL(requestFinished(int, bool)), this, SLOT(httpRequestFinished(int, bool)));
	connect(http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), this, SLOT(readResponseHeader(const QHttpResponseHeader &)));
(dass ich keinen Progressdialog habe ist auch gewollt)


Danke schon mal im voraus :)


EDIT: QTimer, nicht QSleep *ditch*
Quidquid latine dictum sit, altum sonatur
patrik08
Beiträge: 746
Registriert: 27. Februar 2006 10:48
Wohnort: DE Freiburg

Beitrag von patrik08 »

Von mir aus ist diese qthttp request method nicht stark genug... fuer dein zwecke ... was wenn der andere server ein cookie setzen moechte bei dir ... oder user & pass oder nur bestimte user_agent zulast? wie so oft mit google...
oder was immer mehr passiert ein redirect url? neue seite.. ....

ich habe mit lib curl eine funktion gemacht die das file via get nimmt wie ein normaler browser ... mit time-out...

code => http://www.qtforum.de/forum/viewtopic.p ... light=curl

und curl kann auch grosse file ziehen ... und wieder aufbauen ... und hat auch einen callback das dir anzeigt von 1 bis 100 vo man gerate ist...

mit curl kann man sehr viel anrichten und lauf auch auf alle os...
Klaue
Beiträge: 13
Registriert: 13. Januar 2006 13:21

Beitrag von Klaue »

Danke, aber QHttp reicht schon. Der User kann nicht selber bestimmen welche Dateien. Alles nu zu erklären wär zu umständlich, aber man kann es so sehen: Alle Dateien, die angefordert werden können, liegen auf ein und demselben server. Diesem sind referer, user agent etc herzlich egal ;) auch Username/Passwort brauchts nicht.

Werd mir aber Morgen trotzdem mal die CUrl-Version ansehen. Auch wenn das wieder zusatzlibs gibt, nehm ich an. Aber kann ja sein, dass die bei meinem Problem helfen kann
Danke
Quidquid latine dictum sit, altum sonatur
Shadow
Beiträge: 92
Registriert: 27. August 2005 18:15
Wohnort: Iserlohn
Kontaktdaten:

Re: File downloaden in nur einem Thread

Beitrag von Shadow »

Klaue hat geschrieben:Hallo zusammen.
Ich habe da so ein kleines Problem.
Ich will eine Datei runterladen. Das funktioniert auch. Da ich aber mehrere Dateien runterladen will, habe ich mir eine Funktion gebastelt, die die Adresse der Datei und den lokalen Dateinamen als Parameter bekommt.
Mein Problem ist nun, dass diese funktion erst zurückkehren sollte, wenn die Datei Fertig runtergeladen ist. So wie ich das aber jetzt habe, wird die Datei in einem neuen Thread runtergeladen während das Hauptprogramm weiterläuft.
Ich könnte jetzt im Hauptprogramm einen while(true)-loop einbauen, der per if einen boolean abfragt und erst, falls dieser true sein sollte, den loop beendet. Den boolean könnte ich per Extrafunktion und dem Signal requestFinished setzen. Ich finde diese "Lösung" aber ziemlich hässlich, ausserdem würde die (soweit ich mich erinnere) den Prozessor ziemlich auslasten, bis die Datei gedownloaded ist.
Ich habe auch schon QTimer in betracht gezogen, aber da das auch nur ein Signal sendet, würde es auf dasselbe rauskommen.
Daher wollte ich fragen, ob hier jemand wüsste, wie ich das besser hinkriegen könnte oder eine alternative Downloadart wüsste.
Wenn Du dafür schon extra mit Threads arbeitest, warum machst du das nicht so, das du noch einen Thread für einen gemeinsamen Resourcenblock verwendest, der diese Schleife enthält. Das würde die ganze Anwendung stark entlasten und wärst auch rechtzeitig über Statusänderungen informiert.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: File downloaden in nur einem Thread

Beitrag von Christian81 »

Klaue hat geschrieben: Ich könnte jetzt im Hauptprogramm einen while(true)-loop einbauen, der per if einen boolean abfragt und erst, falls dieser true sein sollte, den loop beendet. Den boolean könnte ich per Extrafunktion und dem Signal requestFinished setzen.
Warum in einer Schlife warten wenn Du ein Signal abschickst? Man kann doch einfach auf das Signal reagieren und in dem Slot dann die nächste Datei anfordern... ?
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Shadow
Beiträge: 92
Registriert: 27. August 2005 18:15
Wohnort: Iserlohn
Kontaktdaten:

Re: File downloaden in nur einem Thread

Beitrag von Shadow »

Christian81 hat geschrieben:
Klaue hat geschrieben: Ich könnte jetzt im Hauptprogramm einen while(true)-loop einbauen, der per if einen boolean abfragt und erst, falls dieser true sein sollte, den loop beendet. Den boolean könnte ich per Extrafunktion und dem Signal requestFinished setzen.
Warum in einer Schlife warten wenn Du ein Signal abschickst? Man kann doch einfach auf das Signal reagieren und in dem Slot dann die nächste Datei anfordern... ?
Korrekt, bin heute wohl noch nicht ganz wach... :wink:
Klaue
Beiträge: 13
Registriert: 13. Januar 2006 13:21

Beitrag von Klaue »

Ich selber mache keine mehrfachen Threads (ich blick bei Threads sowieso nie so ganz durch :roll: ), QHttp macht das von sich aus. Und mit dem Signal die nächste Funktion starten geht leider auch nicht, da ich zu verschiedenen Zeiten verschiedene Dateien benötige. Je nachdem was der User eingibt oder wo er klickt halt andere, deren Namen dynamisch erstellt werden (die weiss ich at compiletime noch ned). Auch sonst geht das mit dem Signal abfangen glaube ich nicht, denn.. Angenommen ich wäre dann bei der letzten datei angekommen.. ich gaub nicht, dass ich die connects nur für die letzte datei ändern kann. ich könnte höchstens die Slotfunktion mit nem Haufen ifs versehen.
Der Grund, warum ich das in eine Funktion stecken wollte ist ja, dass ich überall wenns benötigt wird einfach nur die Funktion aufrufen kann und dann die Datei zur Verfügung habe. Also so in der Art:

Code: Alles auswählen

[...]
string sFilename = (was auch immer);
string sLocation = (was auch immer);

downloadFile(sLocation, sFilename);

ifstream inpFil;
inpFil.open("sFilename");
if (!inpFil.is_open()) {
	cout << "Couldn't open file" << endl;
	exit (1);
}
char cTemp[10000];
string sTemp;
while (inpFil) {
       	inpFil.getline(cTemp, 10000);
       	if (inpFil) {
		sTemp = cTemp;
		// do something
	}
}
inpFil.close();
[...]
Müsste das nicht irgendwie machbar sein?
Quidquid latine dictum sit, altum sonatur
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Ich verstehe nicht wo das Problem ist...
Mit http://doc.trolltech.com/4.1/qhttp.html#get die Datei(en) anfordern und auf das Signal http://doc.trolltech.com/4.1/qhttp.html#requestFinished reagieren. Fertig.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Klaue
Beiträge: 13
Registriert: 13. Januar 2006 13:21

Beitrag von Klaue »

Das Problem ist, dass es mit den Dateien nicht immer nur dasselbe machen soll. Wenn ich das mit dem Signal abfange, komme ich damit ja immer nur zu ein-und derselben Funktion. Und da alles mit ifs etc abzufangen find ich recht Umständlich (und Suboptimal (ich liebe dieses Wort :))). Ich würde es Toll finden, wenn ich einfach ne Funktion zum Downloaden aufrufen und gleich nach dem Aufruf weitermachen könnte. Also sicher sein, dass die Datei nach dem return dieser Funktion vorhanden ist.
Ich könnte zwar machen, dass das Signal eine Funktion aufruft, die einen bool setzt und im Programm nach dem Aufruf meiner getfile-Funktion einen while(!bDownloaded) { /*do nothing*/ } oder so machen, was ich aber auch recht unschön fände.
Aber so wie es Aussieht ist das, was ich möchte, wohl nicht möglich (oder ich bring's einfach nicht fertig, es so zu erklären, dass es auch jemand Anderes als ich kapiert)
Quidquid latine dictum sit, altum sonatur
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Aber irgendwo musst Du doch eh zu verschiedenen Funktionen verzweigen (um eben immer was anderes auszuführen). Warum also nicht im Slot? so schwer wird das ja nicht sein...
Einfach nach dem QHttp::get() deine Aktion in eine Map packen (QMap<int ID, enum DeineAktion>) und bei QHttp::requestFinished() in dieser Map nach der ID suchen und die Aktion per switch-Statement aufrufen. Irgendwo musst Du ja die verschiedenen Funktionen aufrufen... !?
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Klaue
Beiträge: 13
Registriert: 13. Januar 2006 13:21

Beitrag von Klaue »

Ich werd es mal so probieren wie du sagst. Ich weiss nicht, wie schnell ich wieder dazu komme, an dem Programm zu arbeiten, also könnte ne ev. Rückmeldung auch ein wenig Zeit beanspruchen.
Quidquid latine dictum sit, altum sonatur
Antworten