QFTP

Alles rund um die Programmierung mit Qt
daffi
Beiträge: 23
Registriert: 2. Januar 2011 18:44

QFTP

Beitrag von daffi »

Hi Leute,

ich schreibe ein Programm, wobei ich auf einen FTP Server zugreifen muss.

Ich wollte dies am FTP von Trolltech testen. Leider funktioniert mein Code nicht.

Code: Alles auswählen

void ftp(){
	QFile *file = new QFile( "test.txt" );

	QFtp *ftp = new QFtp();

	ftp->setTransferMode(QFtp::Active);
	ftp->connectToHost("ftp.trolltech.com");  
	ftp->login();                           
	ftp->cd("qt");                      
	ftp->get("INSTALL",file,QFtp::Binary);               
	ftp->close(); 

}
Wo liegt mein Fehler? Die Text.txt existiert schon aber leider schreibt er nix rein.
Hab ich was übersehen?
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Die Datei sollte man schon öffnen...

Das funktioniert prima bei mir:

Code: Alles auswählen

#include <QCoreApplication>
#include <QFtp>
#include <QFile>

int main(int argc, char ** argv)
{
  QCoreApplication app(argc, argv);
  
  QFile *file = new QFile( "C:\\Devel\\THP\\tmp\\test.txt" );
  file->open(QIODevice::ReadWrite);
  
  QFtp *ftp = new QFtp();
  
  ftp->setTransferMode(QFtp::Active);
  ftp->connectToHost("ftp.trolltech.com"); 
  ftp->login();                           
  ftp->cd("qt");                     
  ftp->get("INSTALL",file);               
  ftp->close();
  
  QObject::connect(ftp, SIGNAL(done(bool)), &app, SLOT(quit()));
  
  int ret = app.exec();
  
  delete ftp;
  delete file;

  return ret;
}
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
daffi
Beiträge: 23
Registriert: 2. Januar 2011 18:44

Beitrag von daffi »

ja das mit dem öffnen hat ich auch schon gesehen...einfach vergessen.
void DeviceRoutine::ftp(){

//Wenn FTP aus ist mache nichts
if (ui.checkBox_FTP->isChecked()==0)
return;


QFile *file = new QFile( "C:\\Users\\Daffi\\Desktop\\test.txt" );
if (file->exists())
file->remove();

file->open(QIODevice::ReadWrite);

QFtp *ftp = new QFtp();

ftp->setTransferMode(QFtp::Active);
ftp->connectToHost("ftp.trolltech.com");
ftp->login();
ftp->get("robots.txt",file);
ftp->close();

file->close();
delete ftp;
}
Das File ist immer wieder leer...was ist nun anders als in deinem Beispiel?

EDIT: Habe gerade gemerkt um die connect Aufrufe komme ich nicht drum herum.
Habs bis grade probiert,komme aber leider nicht weiter.

Ziel ist es von einer Anwendung über das klicken einer checkbox ein gesamtes Verzeichnis zu laden.
(geht es auch mit einem Buffer anstatt des Ladens jeder einzelnen Datei?)

Beispiele wären echt nett.
Das FTP Beispiel von QT finde ich sehr überladen und das mit dem Connect z.B wird nicht klar ersichtlich.

MfG
Daffi
pfid
Beiträge: 535
Registriert: 22. Februar 2008 16:59

Beitrag von pfid »

Also hier:

http://doc.qt.nokia.com/4.7/qftp.html#details

steht doch relativ einfach und un-überladen, wie es funktioniert. Dann kommst du sicher drauf, was das problem ist...
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Code: Alles auswählen

file->close();
delete ftp; 
Wie soll das funktionieren wenn man die Doku liest...
The class works asynchronously, so there are no blocking functions. If an operation cannot be executed immediately, the function will still return straight away and the operation will be scheduled for later execution. The results of scheduled operations are reported via signals. This approach depends on the event loop being in operation.
Des weiteren sollte man wie beschrieben QNetworkAccessManager benutzen.

Code habe ich gezeigt. Der funktioniert!
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
daffi
Beiträge: 23
Registriert: 2. Januar 2011 18:44

Beitrag von daffi »

Also ich verstehe eines nicht.

Christians Programm geht ohne Probleme...
Ich möchte dies aber ohne das QCoreApplication machen (weil argc und argv) nicht bekannt sind.

sobald ich den Teil raus lasse geht es wieder nicht.
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Warum sollten argc und argv nicht bekannt sein?

Warum schreibst du nicht gleich, daß du keine QCoreApplication verwendest, wie soll den eine Event-Routine abgehandelt werden?
daffi
Beiträge: 23
Registriert: 2. Januar 2011 18:44

Beitrag von daffi »

QCoreApp ist doch eine Konsolen App, richtig?

Ich schrieb oben folgendes:
Ziel ist es von einer Anwendung über das klicken einer checkbox ein gesamtes Verzeichnis zu laden.
(geht es auch mit einem Buffer anstatt des Ladens jeder einzelnen Datei?)
CHeckBox != Konsole

Ziel ist es, wenn irgendwann jemand die Box drückt, dass
alle Dateien mit einer gewissen Endung gezogen werden.

Dazu wollte ich als Beispiel ersteinmal eine Datei ziehen.

Die Connect Funktion der Checkbox geht und verweist auf meine FTP Funktion :

Code: Alles auswählen

void DeviceRoutine::ftp(){
 
	//Wenn FTP aus ist mache nichts
	if (ui.checkBox_FTP->isChecked()==0)
		return;

	
	QFile *file = new QFile( "C:\\Users\\Daffi\\Desktop\\test.txt" );
	if (file->exists())
		file->remove();

	file->open(QIODevice::ReadWrite); 
	QFtp *ftp = new QFtp();

	ftp->setTransferMode(QFtp::Active);
	ftp->connectToHost("ftp.trolltech.com");  
	ftp->login();               

	ftp->get("robots.txt",file);  
	
	connect(ftp, SIGNAL(done(bool)), this, SLOT(beenden())); 

	delete ftp;
	delete file; 
} 
Allerdings legt er nur eine neue Datei an, der Rest wird nicht getriggert.
Die Frage ist Warum nicht bzw wie mache ich das NICHT auf KonsolenBasis.
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

ARGH! Du schreibst oben
Ich möchte dies aber ohne das QCoreApplication machen (weil argc und argv) nicht bekannt sind.
Niente von wegen GUI. Und für Gui mit Qt brauchst du ein QApplication, was 1) von QCoreApplication abgeleitet ist und 2) auch argc und argv als Parameter erwartet. was bei argc und argv das Problem ist, solltest du bitte mal erklären.

Zu deinem eigentlichen Problem wurde bereits was gesagt. QFtp arbeitet asynchron, ein get() usw. stoßen eine Aktion im Hintergrund an und kehren sofort an die Stelle des Aufrufs zurück. Wenn du danach sofort dein ftp und file zerstörst, werden diese asynchronen Operationen sofort abgebrochen.
Ergo: Schau dass dein ftp und file-Objekt so lange leben, wie sie brauchen die Dateien herunter zu laden.
Und wo du in deinem Code jetzt versuchst ALLE Dateien mit einer bestimmten Endung zu holen seh ich auch nicht - du forderst explizit nur die robots.txt an.

Ich denke du solltest zu allererst C++ ordentlich lernen. (Wg. Verständnis für Objektzugehörigkeiten, Lebenszeit, Instanziierung, usw.), danach die Qt-Grundlagen. Natürlich kannst du das auch parallel zu deinem Projekt machen, aber mMn. besteht da noch etwas Nachholbedarf.
daffi
Beiträge: 23
Registriert: 2. Januar 2011 18:44

Beitrag von daffi »

Em ich glaub du kannst nicht lesen oder wir reden an einander vorbei!

argv und argc sind nicht in meiner Klasse bekannt. (Logisch kommen von der Main)
Da ich aber innerhalb einer Klasse den FTP Transfer durchziehen will und nicht als batch oder sonstiges wüsste ich nicht wie ich dies bewerkstellige.

Das FTp Objekt bleibt lange genug am leben! Schließlich ist es nur 1kb groß und bei Christian gehts genau so mit dem selben Code.

Und ich weis wohl genau das dies noch nicht für alle gilt,denn schließlich ist das ja auch das Ziel und nicht der Ist-Zustand....

wie ich bereits schrieb:
Dazu wollte ich als Beispiel ersteinmal eine Datei ziehen.
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

daffi hat geschrieben:Das FTp Objekt bleibt lange genug am leben! Schließlich ist es nur 1kb groß und bei Christian gehts genau so mit dem selben Code.
Garantiert stirbt dein ftp-Objekt viel zu früh! Ist dir klar, wie schnell dein Rechner mit der get()-Methode durch ist, und was bei einer Verbindung mit einem entfernten FTP-Server an Zeit flöten geht? Oder willst du mir weiß machen, dass deine Internetleitung schneller ist, als die Anbindung deines RAM an die CPU (L1/2/3-Caches mal komplett weggelassen)...
Dass der Code von Christian funktioniert hat einen einfachen Grund.

Code: Alles auswählen

QObject::connect(ftp, SIGNAL(done(bool)), &app, SLOT(quit()));
 
  int ret = app.exec(); 
So lange ftp nicht done() sendet, rödelt die app in der EventLoop rum (app.exec()). Sobald ftp seine Dateien gezogen hat, wird done() emittiert, der angeschlossene app.quit() aufgerufen, was die EventLoop beendet. Jetzt wird app.exec() beendet, und der Code hinter app.exec() abgearbeitet - Dazu zählt auch das delete ftp.

Eine mögliche Lösung: Macht ftp und file zu einem Member deiner Klasse, dann hast du die Objekte und deren Lebenszeit voll in der Hand!
daffi
Beiträge: 23
Registriert: 2. Januar 2011 18:44

Beitrag von daffi »

Ah Ok.Das war die Antwort auf die ich so etwa gewwartet habe.Jetzt ist mir schon einiges klarer.

Gut, gänge theoretisch auch eine while schleife um auf den FTP zu warten?
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

daffi hat geschrieben:Gut, gänge theoretisch auch eine while schleife um auf den FTP zu warten?
Versuch es nicht. Netzwerkzugriffe sind nicht umsonst asynchron. Lass den Server hängen dann hängt auch deine Applikation. Ich würd mich nicht wundern, wenn dir auch der kurze Lock der GUI zu viel wird, und du dann frägst, wie du die Arbeit in nen neuen Thread auslagern kannst :D

Die asynchrone Kommunikation via SIGNAL/SLOT ist bei dem QFtp jetzt wirklich nicht schwer (aufs done warten, bingo). Und eine synchrone API ala waitForFinished() bietet dir AFAIK keine der Qt-Netzwerkklassen.
daffi
Beiträge: 23
Registriert: 2. Januar 2011 18:44

Beitrag von daffi »

wie kann ich dennoch in einer Unterfunktion einer klasse also eine normale memberfunktion eine QCoreApplication erstellen? Weil die brauche ich ja anscheinend...
pfid
Beiträge: 535
Registriert: 22. Februar 2008 16:59

Beitrag von pfid »

daffi hat geschrieben:wie kann ich dennoch in einer Unterfunktion einer klasse also eine normale memberfunktion eine QCoreApplication erstellen? Weil die brauche ich ja anscheinend...
In der Regel wird das so wie in Christians Beispiel gemacht. In deiner main-Funktion wird ein Q(Core-)Application Objekt erstellt, und mit app.exec (siehe christians Beispiel..) die Event-Loop gestartet. Zwischen erstellen der Q(Core-)Application und dem Starten der Event-Loop legst du dann dein Hauptfenster o.ä. an (siehe christians Beispiel..).

In deiner Unterfunktion deiner Klasse brauchst/sollst/darfst du keine QCoreApplication erstellen. Siehe hier:

http://doc.qt.nokia.com/4.7/gettingstartedqt.html
Antworten