Mit TCP eine Datei auf FTP server hochladen/runterladen

  • Hallo

    mir ist die idee gekommen Dropbox nachzuprogrammieren (ICH WILL
    >nicht< DROPBOX NUTZEN UND AUCH KEINE ANDERE PROGRAMME) und wollte
    mal fragen, da ich tcp neu entdeckt habe, per tcp dateien auf mein ftp
    server hochzuladen,

    wenn das gehen sollte, wie geht es?

    was ich bräuchte wäre evtl ein beispiel/tutorial oder gegebenenfalls ein paar Befehle die ich dazu benötige

    mfg,thx

  • Ja, das geht. Dafür musst du dich 1) natürlich mit den TCP Befehlen auskennen und 2) dich mit dem FTP-Protokoll auseinandersetzten. Hier ist eine nützliche Seite mit einer Beschreibung von FTP, Befehlsliste uvm.

    Wenn du keine Lust hast, dir alles zusammenzubasteln, kannst du auch die AutoIt FTP Funktionen verwenden, aber die sind nicht immer das Wahre :S

  • Die Frage ist doch, wieso du überhaupt TCP verwenden willst. Denn dann müsstest du erst das FTP-Protokoll in AutoIt implementieren, um mit den TCP-Funktionen die Dateien auf deinem FTP-Server zu verwalten.

    Die in AutoIt mitgelieferten FTP-Funktionen zu benutzen wäre meiner Meinung nach besser:

    Spoiler anzeigen
    [autoit]


    _FTP_Close
    _FTP_Command
    _FTP_Connect
    _FTP_DecodeInternetStatus
    _FTP_DirCreate
    _FTP_DirDelete
    _FTP_DirGetCurrent
    _FTP_DirPutContents
    _FTP_DirSetCurrent
    _FTP_FileClose
    _FTP_FileDelete
    _FTP_FileGet
    _FTP_FileGetSize
    _FTP_FileOpen
    _FTP_FilePut
    _FTP_FileRead
    _FTP_FileRename
    _FTP_FileTimeLoHiToStr
    _FTP_FindFileClose
    _FTP_FindFileFirst
    _FTP_FindFileNext
    _FTP_GetLastResponseInfo
    _FTP_ListToArray
    _FTP_ListToArray2D
    _FTP_ListToArrayEx
    _FTP_Open
    _FTP_ProgressDownload
    _FTP_ProgressUpload
    _FTP_SetStatusCallback

    [/autoit]


    Falls du es allerdings doch mit den TCP-Funktionen machen willst, solltest du dir RFC 959 anschauen.

    MfG, James

    Edit: Cheater Dieter war schneller...

  • Dankeschön soweit,
    gibt es keine möglichkeit dateien auf ein ftp server zu laden (möglichst einfach ohne die eigentlichen ftp befehle zu nutzen)?
    ich hätte jetzt noch 2 fragen,

    erstmal wie kann ich alle dateien und unterordner in einem Ordner auslesen lassen?

    dann noch was könnte man mit tcp sinnvolles machen auser ein chat?
    mfg

  • Wie schon von meinen Vorrednern richtig erkannt ist das unnötige Arbeit, denn alle wichtigen FTP Funktionen wurden bereits in Autoit umgesetzt.

    Was man mit TCP noch so alles sinnvolles anstellen kann? Du könntest z.B. dein eigenes Kommunikationsprotokoll entwickeln. Das kann man dann nutzen um zwischen eigenen Scripten zu kommunizieren, sei es Übertragen von kleineren Datenmengen wie Steuerbefehlen, Variablen oder gar kompletter Dateien, ähnlich wie beim FTP Protokoll. Du könntest damit auch eine Remotesteuerung einer von dir entwickelten Anwendung realisieren, so dass du diese weltweit bedienen kannst ohne dafür auf andere Remoteanwendungen wie Windows Remotedesktop oder ein Webinterface angewiesen zu sein.

  • ok vielen dnak für die ideen
    ich setze erstmal das dropbox teil um :)

    aber das problem ist wie kann ich:
    - alle dateien und unterordner in einem Ordner auslesen lassen?
    - alle dateien und unterodner auf dem ftp server in einem ordner auslsesen lassen? (_ftp_filelist2array oder so ähnlich liest ja nur die dateien aus (?))

  • Dann liest du eben den Ordnerinhalt in ein Array, und überprüfst beim Durchgehen, ob das aktuelle Element ein Ordner ist. Wenn ja, dann listest du in diesem wieder alle Dateien/Ordner auf und immer so weiter. Und am Ende hast du dann ein Array (oder auch mehrere, je nach dem wie du es löst) in dem alle Dateien in allen Ordnern auf dem Servern eingetragen sind.

  • ja gut, welche befehle brauche ich dafür?
    bestimmt stringregexp?

    Spoiler anzeigen
    [autoit]

    Func _searchFiles($path, $iMode = 0, $TrimPath = "")
    Local $rFiles = ""

    [/autoit] [autoit][/autoit] [autoit]

    ;If StringRight($path, 1) <> "\" Then $path &= "\"
    $hSearch = FileFindFirstFile($path & "*.*")
    If @error Or $hSearch = -1 Then Return SetError(-1, "", "")
    While 1
    $sfile = FileFindNextFile($hSearch)
    If @error Then ExitLoop
    If @extended Then
    $rFiles &= _searchFiles($path & $sfile & "\", 0, $TrimPath)
    Else
    $rFiles &= StringTrimLeft($path & $sfile & @CR, StringLen($TrimPath))
    EndIf
    WEnd
    FileClose($hSearch)
    If $iMode = 1 Then Return StringSplit(StringTrimRight($rFiles, StringLen(@CR)), @CR)
    _FTPFilePutSingleFile($rFiles)
    EndFunc

    [/autoit]

    nutze ich um jetzt die test.txt rauszuholen aber die will nicht hochgeladne werden :o

    so sieht mein scirpt aus (daten geändert ;) es kommt als error -1 beim upload)

    Spoiler anzeigen
    [autoit]

    #include <FTPEx.au3>
    #include <File.au3>
    #include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $Name = "Sync"
    $Ordner = @AppDataDir & "\" & $Name & "\"
    Global $ServerName = 'ft'
    Global $Username = "ftp18"
    Global $Password = "lolip9"
    Global $LocalFile = $Ordner & "test.txt"
    Global $RemoteFile = "/test.txt"

    [/autoit] [autoit][/autoit] [autoit]

    If Not FileExists($Ordner) Then
    DirCreate($Ordner)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    _searchFiles($Ordner)

    [/autoit] [autoit][/autoit] [autoit]

    Func _searchFiles($path, $iMode = 0, $TrimPath = "")
    Local $rFiles = ""

    [/autoit] [autoit][/autoit] [autoit]

    ;If StringRight($path, 1) <> "\" Then $path &= "\"
    $hSearch = FileFindFirstFile($path & "*.*")
    If @error Or $hSearch = -1 Then Return SetError(-1, "", "")
    While 1
    $sfile = FileFindNextFile($hSearch)
    If @error Then ExitLoop
    If @extended Then
    $rFiles &= _searchFiles($path & $sfile & "\", 0, $TrimPath)
    Else
    $rFiles &= StringTrimLeft($path & $sfile & @CR, StringLen($TrimPath))
    EndIf
    WEnd
    FileClose($hSearch)
    If $iMode = 1 Then Return StringSplit(StringTrimRight($rFiles, StringLen(@CR)), @CR)
    _FTPFilePutSingleFile($rFiles)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _FTPFilePutSingleFile($LocalFile)
    $FTPOpen = _FTP_Open($Name)
    $errOpen = @error
    If Not @error Then
    $FTPConnect = _FTP_Connect($FTPOpen, $ServerName, $Username, $Password)
    $errFTP = @error
    If Not @error Then
    MsgBox(1,$RemoteFile,$LocalFile)
    $LocalFile = $LocalFile
    If _FTP_FilePut($FTPConnect, $LocalFile, $RemoteFile) Then
    ConsoleWrite("Upload: erfolgreich" & @CRLF)
    Else
    ConsoleWrite("Upload: fehlgeschlagen " & " " & @error & @CRLF)
    EndIf
    Else
    MsgBox(0, "Connect", "fehlgeschlagen")
    ConsoleWrite("Connect: " & " " & $errFTP & @CRLF)
    EndIf
    Else
    MsgBox(0, "Open", "fehlgeschlagen")
    ConsoleWrite("Open " & " " & $errOpen & @CRLF)
    EndIf
    _FTP_Close($FTPOpen)
    EndFunc

    [/autoit]

    3 Mal editiert, zuletzt von Zattoo (22. August 2012 um 10:56)

  • Warum solltest du dafür reguläre Ausdrücke benötigen? Du brauchst viel eher Rekursion, also eine sich selbst aufrufende Funktion.


    Diese beiden Befehle reichen völlig um eine in sich verschachtelte Ordnerstruktur auf einem FTP bzw. lokal auf der HDD zu analysieren, beide können dir Informationen über vorhandene Unterverzeichnisse liefern, danach machst du das selbe mit allen gefundenen Unterverzeichnissen usw.

    [autoit]


    _FTP_ListToArray()
    _filelisttoarray()

    [/autoit]


    Beispiel um alle Unterverzeichnisse eines Verzeichnisses zu finden:


    [autoit]


    #include <array.au3>
    #include <file.au3>

    [/autoit][autoit][/autoit][autoit]

    global $aResult[1]
    $mainfolder="C:\Windows\System32\"

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    getallsubfolders($mainfolder,$aResult)
    _arraydisplay($aResult)

    [/autoit][autoit][/autoit][autoit]

    func getallsubfolders($folder, $array)

    local $aTemp

    $aTemp = _filelisttoarray($folder,"*",2)
    if $aTemp = 0 then return

    [/autoit][autoit][/autoit][autoit]

    for $i=1 to $aTemp[0]
    _arrayadd($aResult,$folder & $aTemp[$i] & "\")
    getallsubfolders($folder & $aTemp[$i] & "\", $aResult)
    next

    [/autoit][autoit][/autoit][autoit]

    endfunc

    [/autoit]
  • also ist meine funktion nicht das richtige?

    das ist jetzt für die einfachen dateien zu finden und hochzuladen:

    [autoit]

    Func _GetAllFiles()
    $FileList = _FileListToArray($Ordner, "*", 1)
    For $i = 1 To $FileList[0]
    _FTPFilePut($Ordner & $FileList[$i], $FileList[$i])
    Next
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func _GetAllSubFolders()
    $SubFolderList = _FileListToArray($Ordner, "*", 2)
    For $i = 1 To $SubFolderList[0]
    _FTP_DirCreate($FTPConnect, $SubFolderList[$i])
    Next
    EndFunc

    [/autoit]

    korrekt so?
    funkt nämlich 1a ;)
    YOU MAD BROOOO !? es geht :D hab arrays nie gecheckt aber jetzt isses echt easy going

    so problem ist jetzt nurnoch wie ich in ordner die dateien und ordner auslese, wenn das ordner in ordner in ordner in ordner in ordner blablabla ist, wie regel ich das am bangerangsten?
    mfg

    2 Mal editiert, zuletzt von Zattoo (22. August 2012 um 12:34)

  • Zitat

    also ist meine funktion nicht das richtige?


    Keine Ahnung, ich hatte mein Beispielscript noch vor deinem Edit geschrieben und deine Funktion nicht angeschaut. Ich persönlich nutze lieber _filelisttoarray als die nativen filefindfirst/next Funktionen, da dies einfacher zu handhaben und übersichtlicher ist. Grundsätzlich nutzt du aber ebenfalls Rekursion wenn ich das richtig sehe, aber ob das so alles richtig ist kann ich dir jetzt auch nicht sagen, hab keine Zeit / Lust das zu testen.

    Richtig oder Falsch gibt es ohnehin nicht, viele Wege führen nach Rom. ;)

    Bei meinem Beispielscript hättest du nun zumindestens ein Array mit der kompletten Ordnerstruktur und jenachdem was du nun eigtl tun willst kannst du diese Daten wunderbar in Schleifen verwenden um z.B. die FTP Ordnerstruktur mit der lokalen Ordnerstruktur zu vergleichen und dann je nach Fall Dateien oder ganze Ordner uploaden/downloaden oder eben nichts tun.

    PS:
    Soweit ich das sehe erstellt deine Funktion einen verketteten String mit allen Dateien. Das wird dann vermutlich deshalb nicht funktionieren, weil deine Uploadfunktion nur eine einzige Datei haben möchte und nicht weiß was sie mit solch einem verketteten String anfangen soll. Sie heisst ja vermutlich nicht umsonst fileputsinglefile :D

    EDIT:

    Zu deinem erneuten Edit... jetzt hast du aber keine Rekursion mehr. Wenn du Unterordner und deren Dateien berücksichtigen willst benötigst du die Rekursion aus meinem Beispiel.
    Hier mal ein Beispiel wie du die Dateien aller Ordner aus meinem Unterordnerbeispielscript von oben bekommst:


    [autoit]


    global $aFiles[1]
    getfilesfromfolders($aResult)

    [/autoit][autoit][/autoit][autoit]

    _arraydisplay($aFiles)

    [/autoit][autoit][/autoit][autoit]

    func getfilesfromFolders($aFolders)

    [/autoit][autoit][/autoit][autoit]

    local $aTemp

    [/autoit][autoit][/autoit][autoit]

    for $i=1 to ubound($aFolders)-1
    $aTemp= _filelisttoarray($aFolders[$i],"*",1) ; nur dateien
    if $aTemp = 0 then continueloop
    for $j=1 to $atemp[0]
    _arrayadd($aFiles,$Afolders[$i] & $aTemp[$j])
    next
    next

    [/autoit][autoit][/autoit][autoit]

    EndFunc

    [/autoit][autoit][/autoit][autoit][/autoit]

    Einmal editiert, zuletzt von misterspeed (22. August 2012 um 12:47)

  • die hieß nur sinlgefileput weil ich 2 funktionen hatte und coole namen brauchte :D
    ahso dh ich muss immer in einer for schleife eine for schleife für den nächstes ordner haben?
    ich komm da manchma net mit, ich habs mit den2 funktionen jetzt so,das die dateien und ordner hochgeladen werden
    ich komme mit dem rekursiven nicht mit, ich weiß das in der funktion wenn das und das zutrifft/oder nicht nochmal die gleiche funktion kommt aber so klar ist mir das alles nicht :/

  • Also nochmal etwas Erklärung zu meinen Beiden Beispielen.

    Im ersten Beispiel ermittle ich alle Ordner und deren Unterordner und deren Unterordner usw.
    Das mache ich in dem ich zuerst die Ordner des Hauptordners ermittle. Nun gehe ich alle Ordner des Hauptordners durch und prüfe durch erneuten Aufruf der Funktion ob sich in diesem Ordner ebenfalls Ordner befinden, wenn ja werden diese Ordner erneut durch Aufrufe der Funktion geprüft. Sobald ein Ordner keine Ordner mehr enthält wird eine Ebene darüber der nächste Ordner auf Unterordner geprüft. Das geht solange, bis das Script wieder am Anfang angekommen ist, also im letzten Ordner des Hauptordners. Am Ende sind wir durch alle Ordner gegangen und haben uns diese in einem Array gespiechert.


    Beispeilstruktur:

    Code
    Hauptordner
     -Ordner1
       --Unterordner1a
       --Unterordner1b
     -Ordner2
       --Unterodner2a
     -Ordner3


    Scriptablauf:

    1. Liste Hauptordner erstellen
    2. Liste Ordner1 erstellen -> Funktion wird neu mit gewünschtem Ordner1 aufgerufen
    3. Liste Unterordner1a erstellen -> Funktion wird neu mit gewünschtem Unterordner1a aufgerufen
    4. Unterordner1a enthält keine Ordner mehr, alo $aTemp=0 --> return
    5. Liste Unterodner1b erstellen -> Funktion wird neu mit gewünschtem Unterordner1b aufgerufen
    6. Unterordner1b enthält keine Ordner mehr, alo $aTemp=0 --> return
    7. Liste Ordner2 erstellen -> Funktion wird neu mit gewünschtem Ordner2 aufgerufen
    ....

    Das zweite Script macht nun folgendes:

    Wir haben ein Array mit allen Ordnern aus der ersten Funktion von oben, nun gehen wir in der äusseren For Schleife alle Ordner durch. Für jeden Ordner erstellen wir eine Dateiliste und jede dieser Dateinamen (innere For Schleife) inklusive zugehörigem Ordnerpfad schreiben wir in das Ergebnis Array. Wenn einer der Ordner aus der äusseren Schleife keine Dateien enthält, dann überspringen wir diesen Ordner mit continueloop.

    Scriptablauf:

    1. Erster Ordner der Ordnerschleife ist dran
    2. Dateiliste des ersten Ordners erstellen
    3. innere Schleife, jede gefundene Datei aus dem ersten Ordner in ein Array speichern
    4. Zweiter Ordner ist dran
    ...


    Hoffe nun verstehst du in etwa was da passiert.

  • gott wie doof :D
    ich adchte das wäre nur zum lesen der hauptordner..
    ich schaue es mir mal genauer an

    also habs jetzt gecheckt, er erstellt zwar ordner aber keine unterordner, der ballert einfach alle ordner ins hauptverzeichnis

    [autoit]

    getallsubfolders($Ordner,$aResult)

    [/autoit][autoit][/autoit][autoit]

    func getallsubfolders($Ordner, $array)

    [/autoit][autoit][/autoit][autoit]

    ;local $aTemp

    [/autoit][autoit][/autoit][autoit]

    $aTemp = _filelisttoarray($Ordner,"*",2)
    if $aTemp = 0 then return

    [/autoit][autoit][/autoit][autoit]

    for $i=1 to $aTemp[0]
    _FTP_DirCreate($FTPConnect, $aTemp[$i])
    getallsubfolders($Ordner & $aTemp[$i] & "\", $aResult)
    next

    [/autoit][autoit][/autoit][autoit]

    endfunc

    [/autoit]
  • Das geht so auch nicht. Schon alleine deswegen, weil die lokalen Pfade "C:\blah\" lauten. Auf dem FTP lauten die Pfade nachher aber "\blah\".
    Trenn doch einfach Datenermittlung von produktiven Funktionen wie deinem FTP Upload. Hast du erstmal alle Daten in Arrays ist es viel einfachher diese in modifizierter Form für die FTP Kommandos zu nutzen.

    Angenommen du hast meine vollständige Ordnerliste aus Beispiel 1

    [autoit]


    for $i=1 to ubound($aResult)-1
    _FTP_DirCreate($FTPConnect, stringtrimleft($aResult[$i]),2))
    ;oder
    _FTP_DirCreate($FTPConnect, stringreplace($aResult[$i]),"c:\testpfad\teil_des_pfades_der_weg_soll_und_nix_auf_dem_ftp_verloren_hat",""))
    next

    [/autoit][autoit][/autoit][autoit][/autoit]
  • ok,
    ich bin jetzt soweit, er erstellt Ordner und Dateien, das Problem ist nur:
    es ist so aufgebaut

    Ordner/SubOrdner/SubSubOrdner/test.txt
    Ordner2/test.txt
    Ordner3/SubOrdner3/SubSubOrdner/test.txt
    Ordner4/test.txt
    test.txt

    erstellt: grün
    nicht erstellt: rot

    es fällt auf das er die letzte datei im letzten ordner nicht erstellt :/

    Spoiler anzeigen
    [autoit]


    Func _FTPFilePut($LocalFile, $RemoteFile)
    If _FTP_FilePut($FTPConnect, $LocalFile, $RemoteFile) Then
    ConsoleWrite("Upload: Erfolgreich (" & $LocalFile & ")" & @CRLF)
    Else
    ConsoleWrite("Upload: Fehlgeschlagen (" & @error & ") (" & $LocalFile & ")" & @CRLF)
    EndIf
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _PutAllFiles($LocalPath)
    $FileList = _FileListToArray($LocalPath, "*", 1)
    If $FileList = 0 Then Return
    For $l = 1 To $FileList[0]
    _FTPFilePut($LocalPath & $FileList[$l], $FileList[$l])
    Next
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _PutAllFolders($LocalPath, $SubPath = "0")
    $LocalFolderList = _FileListToArray($LocalPath, "*", 2)
    If $LocalFolderList = 0 Then Return
    If @error = 4 Then $SubPath = "0"
    For $i = 1 To $LocalFolderList[0]
    If $SubPath = "0" Then
    _FTP_DirSetCurrent($FTPConnect, "/")
    Else
    _FTP_DirSetCurrent($FTPConnect, $SubPath)
    EndIf
    If _FTP_DirCreate($FTPConnect, $LocalFolderList[$i] & "/") Then
    ConsoleWrite("FTPDirCreate: Erfolgreich (" & $LocalFolderList[$i] & ")" & @CRLF)
    Else
    ConsoleWrite("FTPDirCreate: Fehlgeschlagen (" & @error & ") ("& $LocalFolderList[$i] & ")" & @CRLF)
    EndIf
    _PutAllFiles($LocalPath & $LocalFolderList[$i] & "\")
    _PutAllFolders($LocalPath & $LocalFolderList[$i] & "\", $LocalFolderList[$i])
    Next
    EndFunc

    [/autoit]

    Einmal editiert, zuletzt von Zattoo (25. August 2012 um 13:30)

  • Jetzt liegt es am auflisten der remote ordner auf dem ftp server in arrays:

    Spoiler anzeigen
    [autoit]

    Func _FTPGetAllFolders($FTPPath = "", $FTPSubPath = "0")
    If $FTPSubPath = "0" Then
    _FTP_DirSetCurrent($FTPConnect, "/")
    Else
    _FTP_DirSetCurrent($FTPConnect, $FTPPath & "/")
    EndIf
    ConsoleWrite(_FTP_DirGetCurrent($FTPConnect) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    $FTPFolderList = _FTP_ListToArray($FTPConnect, 1)
    If $FTPFolderList[0] = 0 Then MsgBox(0,"","return")
    For $p = 1 To $FTPFolderList[0]
    If Not StringInStr($FTPPath & $FTPFolderList[$p], ".") Then
    _ArrayAdd($RemoteFolderListResult, $FTPPath & $FTPFolderList[$p])
    _FTPGetAllFolders($FTPPath & $FTPFolderList[$p] & "/", $FTPFolderList[$p])
    EndIf
    Next
    EndFunc

    [/autoit]
  • Spoiler anzeigen
    [autoit]

    Func _FTPGetAllFolders($Folder = "")
    Local $Check
    If $Folder = "" Then
    _FTP_DirSetCurrent($FTPConnect, "/")
    Else
    _FTP_DirSetCurrent($FTPConnect, $Folder)
    EndIf
    $FTPFolderList = _FTP_ListToArray($FTPConnect, 1)
    _ArrayAdd($RemoteFolderListResult, _FTP_DirGetCurrent($FTPConnect))
    If $FTPFolderList = 0 Or $FTPFolderList[0] = 0 Then
    $Check = False
    While $Check = False
    _FTP_DirSetCurrent($FTPConnect, StringLeft(_FTP_DirGetCurrent($FTPConnect), StringInStr(_FTP_DirGetCurrent($FTPConnect), "/", 0, -1) - 1))
    $tmp_FTPFolderList = _FTP_ListToArray($FTPConnect, 1)
    For $i = 1 To $tmp_FTPFolderList[0]
    If _ArraySearch($RemoteFolderListResult, _FTP_DirGetCurrent($FTPConnect) & "/" & $tmp_FTPFolderList[$i]) = -1 Then
    $Check = True
    ExitLoop
    EndIf
    Next
    WEnd
    Return 0
    EndIf
    For $Subfolder = 1 To $FTPFolderList[0]
    _FTPGetAllFolders(_FTP_DirGetCurrent($FTPConnect) & "/" & $FTPFolderList[$Subfolder], 1)
    Next
    EndFunc ;==>_FTPGetAllFolders

    [/autoit]

    Musste die FUnktion etwas umschreiben, aber jetzt gehts ;)

  • vielen dank das du dich drum bemühst, aber bei mir bleibt er rekursiv und will nicht mehr raus (endlos)
    bei meinem script hat er mir aber auch die ordner . und .. angezeigt, die garnicht vorhanden waren :/