[gelöst] Verzeichnis am Server vorhanden ?

Alles rund um die Programmierung mit Qt
hs60
Beiträge: 31
Registriert: 13. Januar 2010 16:54

[gelöst] Verzeichnis am Server vorhanden ?

Beitrag von hs60 »

Hallo allerseits,

Bin am Schreiben eines ftp-Uploaders und stehe dzt. bei folgendem Problem:

Code: Alles auswählen

ftp->MkDir("/test");
funktioniert, wenn das Zielverzeichnis noch nicht vorhanden war.

Wie kann ich abfragen, ob das Zielverzeichnis bereits besteht, bzw. wie kann ich, wenn das Verzeichnis schon besteht und obiger Befehl nochmals abgesandt wird, den Fehler auswerten?

Derzeit wird das Programm bis zu dieser Zeile ausgeführt und stoppt danach.

mfg
Herbert
Zuletzt geändert von hs60 am 26. Januar 2010 17:06, insgesamt 1-mal geändert.
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

der befehl um zu schauen was schon in dem FTP verzeichnis liegt, heisst "List" !
Ich würde fast drauf wetten, das QFtp (ich nehm an darum geht es) irgend was mit List zur verfuegung stellt.

Ne andere chance hasst nich, musst abfragen, oder fehlermeldung abfangen und unterdruecken.

Ciao ...
AuE
Beiträge: 918
Registriert: 5. August 2008 10:58

Beitrag von AuE »

int QFtp::list ( const QString & dir = QString() )
Lists the contents of directory dir on the FTP server. If dir is empty, it lists the contents of the current directory.

The listInfo() signal is emitted for each directory entry found.

The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished().

When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted.

See also listInfo(), commandStarted(), and commandFinished().
hs60
Beiträge: 31
Registriert: 13. Januar 2010 16:54

Beitrag von hs60 »

Vielen Dank vorerst mal für die Antworten.

Da List ja sofort zurückgibt, habe ich keine Möglichkeit, fehlende Verzeichnisse am Server zu erstellen, da ja das Programm in der Zwischenzeit weiterläuft.

Wie kann ich es anstellen, daß das Programm beim Fehlen eines Verzeichnisses so lange anhält, bis mit MkDir das Verzeichnis angelegt wurde. Eine Neuerstellung kann sich auch über mehrere Ebenen (Unterverzeichnisse) erstrecken.

Bei der Auswertung des Fehlers ist es genau so. Wenn ein Fehler zurück gegeben wird und daraufhin das Programm das fehlende Verzeichnis anlegt, sind alle folgenden Befehle bereits abgearbeitet.

Kennt jemand eine Möglichkeit, dieses Problem in den Griff zu bekommen?

mfg
Herbert
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Nö, viel zu wenige Infos ^^
da ja das Programm in der Zwischenzeit weiterläuft.
Du hasst also irgend ein programm, welches du nicht anpassen / modifizieren möchtest, das setzt eine struktur(FTP) aufn server vorraus.

Nu willst du parallel zu dem programm irgendwie die Struktur checken und ggf. ergänzen ? Versteh ich das richtig ?

Wenn nein, wo ist dann dein problem ?

Ciao ...
hs60
Beiträge: 31
Registriert: 13. Januar 2010 16:54

Beitrag von hs60 »

Hallo,

ich möchte einen FTP-Uploader schreiben, welcher in der Lage ist, sämtliche geänderte (Archiv-Bit gesetzt) Dateien eines Verzeichnisses und dessen Unterverzeichnisse in der gleichen Verzeichnisstruktur auf den Server zu übertragen. Das Programm selbst wird stündlich durch ein Fremdprogramm gestartet, soll automatisch ablaufen und sich nach getaner Arbeit beenden.

Im Prinzip funktioniert auch alles, es sei denn, auf dem Server ist ein bestimmtes Verzeichnis nicht vorhanden und muß angelegt werden. Und genau hier ist mein derzeitiges Problem:

Ich übergebe in einer Schleife alle Dateien zum Übertragen und wechsle vor dem ftp-put mittels ftp-cd in das verlangte Serververzeichnis. Wenn dieses Zielverzeichnis bestehend ist, läuft alles wie gewünscht ab. Ist dieses Zielverzeichnis jedoch noch nicht vorhanden, habe ich keine Möglichkeit, mittels ftp-Mkdir dieses Verzeichnis zu erzeugen, da das Programm ja asynchron abläuft und zu diesem Zeitpunkt bereits alle weiteren Befehle abgearbeitet wurden.

Die Auswertung von SIGNAL(commandFinished) zeigt mir zwar den Fehler an, aber ich kann hier nicht eingreifen, da sämtliche weiteren Anweisungen bereits asynchron erledigt wurden.

Ich hoffe, ich konnte mein Problem einigermaßen verständlich erklären.

mfg
Herbert Schneider
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Ich glaub so langsam schnall ichs ^^

Also du uebergibst nen komplettes verzeichniss, inklusive dateien und unterverzeichnisse, und "übertraegst" das in einem rutsch (mit einem Befehl) ???
Das geht mit QFtp ?

Wie wärs, wenn du selber durch die verzeichnisse iterierst, und unterverzeichnisse manuelle anlegst / checkst und die dateien einzeln uebertraegst ?

Ciao ...
hs60
Beiträge: 31
Registriert: 13. Januar 2010 16:54

Beitrag von hs60 »

Hallo,

tut mir leid, daß ich erst jetzt antworten kann...

Ein kleines Missverständnis dürfte noch vorliegen. Selbstverständlich läuft das ganze in einer Schleife ab, in welche jede Datei einzeln übergeben wird:

Code: Alles auswählen

ftp->connectToHost ...
ftp->login();
for (int i = 0; int < AnzahlDateien; i++)
{
  ftp->cd(url.path());     <=== Hier kann der Fehler kommen
  ftp->put(...
}
ftp->close();
Wie gesagt, sobald beim changedir das Zielverzeichnis nicht vorhanden ist, steht ab hier alles.

Verzeichnisse manuell anlegen ist leider nicht möglich, da es sich um einen vollautomatischen Ablauf handelt und gelegentlich neue Verzeichnisse hinzukommen und vom Programm automatisch angelegt werden müssen.

Das zweite Problem, welches sich in diesem Zusammenhang ergibt, ist folgendes:

Sollte ein Übertragunsfehler bei einer einzelnen Datei auftreten, wird die ganze Routine beendet anstatt dass die Übertragung mit der nächsten Datei automatisch fortgesetzt wird.

Ist es überhaupt möglich, mit Qt-eigenen Mitteln ein derartiges Vorhaben zu realisieren oder gibt es ev. second-Hand Routinen, die dafür besser geeignet sind (kein asynchroner, sondern synchroner Ablauf).

mfg
Herbert
hs60
Beiträge: 31
Registriert: 13. Januar 2010 16:54

Beitrag von hs60 »

Kennt jemand eine FTP-Klasse, welche synchron abläuft ?

mfg
Herbert
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Kennt jemand eine FTP-Klasse, welche synchron abläuft ?
FTP wird nie wirklich Synchron laufen, das ist systembedingt.
Du kannst aber synchronitaet "erzeugen".

FTP iss eines der simpelsten TCP-Ip protokollen, du koenntest selber über sockets (QSockets) programmieren, da wuerde Dir sicher einiges "klarer" werden wenn da durch bist.

Aber mit QFtp gehts auch.

Code: Alles auswählen

ftp->cd(url.path());     <=== Hier kann der Fehler kommen
ftp->put(... 
Dein problem, du schickst die Befehle hintereinander ab. du weisst ned wenn die ausgefuehrt werden und ob die ueberhaupt gelingen. Das typisch assynchron.
synchronitaet stellst du her, wenn die den befehl absetzt ftp->cd(url.path()); z.b. und dann erst auf das ergebniss wartest.
Das geht ned ueber den aufruf, der kommt ja sofort zurueck, sondern du musst auf qftp hoeren (signale)
schau dir das Signal "done" bei QFtp an. Das sagt dir ob der Befehl erfolgreich war. Dann kannst entsprechend reagieren bei fehler, oder den naechsten befehl absetzen.
Du musst also viel mehr Eventgesteuert programmieren .... iss erstmal bissi ungewoehnlich, kommst aber ned drumhereum bei allem was assynchron laeuft.

Wo die meisten probleme mit haben an der Stelle, iss das du fuer den "Zustand" deiner Oberflaeche selber verantwortlich bist.
Bei synchroner programmierung rufst die funktion auf, das programm steht bis der aufruf zurueckkommt, fertig.
Bei assynchroner programmierung: die rufst die funktion auf ... funktionsaufruf kommt sofort zurueck, die eigentliche funktionalitaet laeuft im hintergrund. Nu mussst zb. wenn der user warten soll bis die funktion durch is, ihm auch selber alle Bedienmöglichkeiten abklemmen, ergo alle buttons und menues usw. inaktiv schalten und ihm anzeigen das irgendwas im hintergrund tut. Das ist oft viel aufwand, aber du kannst viel mehr realisieren :-) und Fortschrittsanzeigen einbauen geht nur bei (pseudo) assynchronitaet.

Ciao ...
hs60
Beiträge: 31
Registriert: 13. Januar 2010 16:54

Beitrag von hs60 »

Hallo,

vielen herzlichen Dank für die Stellungnahme.

Das Prinzip habe ich jetzt verstanden, nur an der Umsetzung habe ich noch Schwierigkeiten. Wie kann ich auf das Signal warten? Ich habe jetzt eine Signal-Slot Verbindung eingebaut, in der das SIGNAL done von ftp meine Routine doneFtp(bool) aufruft.

Diese 2 Fragen sind mir noch unklar:

1. Was muss ich jetzt in meine doneFtp hineinschreiben ?
2. Wie kann ich im Programm-Ablauf auf das Signal warten ?

Vielleicht kannst du mir hiezu noch ein paar Anstösse geben.

mfg
Herbert
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Wie kann ich auf das Signal warten?
Gar nicht !

Grundlagen GUI programmierung:

Dein programm(Mainthread) befindet sich immer in einer quasi endlos schleife (Windows msgqueue / QT eventqueue) durch "Ereignisse"(usereingabe, Ereignissen von geraeten, "Signale" von aussen) wird dein Mainthread aus der queue geworfen und landet in einer von Dir bereitgestellten Nachrichtenbehandlungsroutine. Wenn die fertig ist, versinkt der thread wieder in der endloasschleife.

Dieses Prinzip sollte dir bei der GUI programmierung (im gegensatz zu den meisten konsolen programmen) ins Blut uebergehen, das brauchst immer wieder.
http://en.wikipedia.org/wiki/Event-driven_programming

Also Fazit, herkoemmliches warten iss nicht. Warten wird umgesetzt durch:
- befehl absetzen, thread in der versenkung verschwinden lassen.
- "ErfolgsmeldeEvent" abfangen und in eigener Routine abhandeln,
- Folge FUnktionalitaet anstossen, bzw Fehlermeldungen generieren.
- Oberflaeche immer auf den (logischen)Status deiner Operation anpassen.

Folgenden prinzipiellen Aufbau braeuchtest Du:
1. - start operation, als slot oder ahnliches
- irgendwo hasst ne struktur aus verzeichnissen und Dateien die zum server uebertragen werden.
- du setzt nen Zeiger / Indikator auf das oberste element(verzeichniss oder datei) zum uebertragen
- du schaltest alle userelemente die stoeren keonnten inaktiv, bzw stellllst sogar noch ein neuese zum abbrechen der Operation zur verfuegung.
- du rufst eine funktion zum abarbeiten deiner Struktur auf.
- danach entlaesst den thread

2. deine funktion zum abarbeiten koennte so aussehen:
- due nimmst das element auf den dein interner Zeiger/indikator zeigt
- je nachdem welcher typ (datei | verzeichniss) rufst du put oder mkdir am Qftp auf.
- du entalesst den thread wieder in die aufruffunktion

3. die reaktion auf das done(Signal -> Slot) koennte so aussehen.
- Result ok -> Zeiger auf der Struktur aufs naechste element setzen
- FUnktion zum abarbeiden deiner Struktur wieder aufrufen.
- result nicht ok. Fehlerstatis setzen, msgbox bringen oder irgendwas. und bedienelemente wieder freigeben. (kann / sollt man auch in ne eigene funktion auslagern)
- Result ok, und zeiger war scho auf dem letzten element -> Erfolgsmeldung und bedienelemente wieder freigeben.


Prinzip verstanden ?

Eigentlich wird dein Fenster damit zum FSM
http://de.wikipedia.org/wiki/Endlicher_Automat
Leute die damit scho mal was zu tun hatten, tun sich da vielleicht leichter.

Ciao ...
hs60
Beiträge: 31
Registriert: 13. Januar 2010 16:54

Beitrag von hs60 »

Nochmals vielen herzlichen Dank für deine sehr ausführliche Dokumentation. Im Prinzip ist mir jetzt alles klar. Ich habe zwischenzeitlich eine Routine (Steuerung) geschrieben, aus der heraus die einzelnen Punkte mit einer ID aufgerufen werden (z.B. als erstes ftp->cd mittels Steuerung(1)). Dann werte ich ftpDone aus und rufe je nach Bedarf den entsprechenden Punkt aus der Steuerung auf.

Code: Alles auswählen

void MainWindow::ftpDone(bool error)
{
  if (error == true)          // Fehler ist aufgetreten
  {
    if (ID == 1) Steuerung(2);    // weiter mit mkdir
    if (ID == 2) Steuerung(1);    // weiter mit cd
  } else {                    // Kein Fehler
    if (ID == 1) Steuerung(3);    // weiter mit put
    if (ID == 2) Steuerung(1);    // weiter mit cd
    if (ID == 3) Steuerung(4);    // weiter mit nächster Datei
  }
}

void MainWindow::Steuerung(int i)
{
  switch (i)
  {
    case 1:           // ftp->cd
      qDebug()  <<  "Steuerung: ID = 1 - url.path = " << url.path();
      ID = 1;
      ftp->cd(url.path());
      break;

    case 2:           // ftp->mkdir
      qDebug()  <<  "Steuerung: ID = 2 - url.path = " << url.path();
      ID = 2;
      ftp->mkdir(url.path());
      break;

    case 3:           // Upload
      qDebug()  <<  "Steuerung: ID = 3 - url.path = " << url.path();
      EineDateiSenden(QuellDatei, dn, "B");
      break;

    case 4:           // Weiter mit nächster Datei aus DateiUploaden
      break;

    default: break;
  }
}
Teilweise funktioniert die Sache schon, allerdings wird die ftpDone() nur bei einem Fehler aufgerufen. Warum ftpDone nach Abarbeitung von z.B. erfolgreichem ftp->cd nicht aufgerufen wird, ist mir noch nicht klar.

Ich habe das Gefühl, dass der Ablauf zwischen den beiden Routinen zu schnell erfolgt, da ftp-cd und ftp-mkdir oft mehrmals hintereinander aufgerufen werden, bis es einmal funktioniert hat.

Ich ersuche nochmals um eine kurze Bestätigung, ob das Prinzip generell verstanden wurde.

mfg
Herbert
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Doku von QFtp lesen:

bei der Beschreibung zum Done steht genau dabei, unter welchen Bedingungen es gefeuert wird. Ausserdem gibt es weitere signale beim QFtp.

Also Dokus sollte man schon lesen, und ggf. die Hilfestellungen die man bekommt dagegen korrelieren und geringfügig anpassen.

Und nein, ich sag Dir jetzt ned welche signale noch für dich intressant sein koennten und warum das done wahrscheinlich ned fliegt :-)
da ftp-cd und ftp-mkdir oft mehrmals hintereinander aufgerufen werden
Genau dafuer ist ein Automat da um das zu steuern, das z.b. immer nur ein befehl aus einer abhaengigen Kette ausgefuehrt wird. Kann dein automat das nicht, ist er fehlerhaft und gehoert überarbeitet :-)

Ciao ...
hs60
Beiträge: 31
Registriert: 13. Januar 2010 16:54

Beitrag von hs60 »

Hurra, es läuft ...

Ich möchte mich noch einmal bei allen Helfenden recht herzlich bedanken. Nach einigem Umkrempeln läuft jetzt alles so, wie ich es will. Wieder um eine Erfahrung reicher ...

mfg
Herbert
Antworten