Daten von einem FTP-Server herunterladen

Veröffentlicht: 2. September 2010 in COM, Dynamics NAV Classic Client, Trick

Ja, auch das geht mit NAV! Allerdings ist Siherunterladencherheit ein nicht ganz so groß geschriebenes Wort an dieser Stelle. Verwendet wird die von ftp.exe von Microsoft. Hierfür kann prinzipiell eine Konfigurationsdatei erstellt werden und per Console (Ausführen –> cmd)  ausgeführt werden. Das bedeutet für uns, dass wir dies in NAV auch nutzen können.

Die Idee

Wir erstellen eine Konfigurations-Datei und verwenden diese direkt per ftp.exe in kombination mit der Console.

Voraussetzungen

Wir benötigen also Benutzername, Passwort, Hostname und Dateiname der zu herrunterladenenen Datei sowie der Pfad, wo diese hingespeichert werden soll.

Die Umsetzung

Wir erstellen eine Codeunit die dafür zuständig ist, Dateien von einem FTP Server herrunter zu laden. Dieser verbindet sich mit einem Benutzerkonto auf einen FTP Server und lädt eine Datei in ein ausgewählten Pfad. In der Codeunit gibt es folgende Funktionen:

  • setHideDialog – Dialogbox ein bzw. auschalten.
  • XENVIRON – Umgebungsvariable abrufen, wird verwendet um die Konfigurationsdatei in den TEMPORARAYPATH zu sichern.
  • FileExists – Kontrolle ob eine Datei schon existiert. Wichtig für Timeout!
  • getFTPData – Daten vom FTP abrufen.

Der Quellcode

Hier der exportierte AL-Code als Textexport:

OBJECT Codeunit 50008 FTP Data
{
  OBJECT-PROPERTIES
  {
    Date=01.09.10;
    Time=12:57:38;
    Modified=Yes;
    Version List=;
  }
  PROPERTIES
  {
    OnRun=BEGIN
            getFTPData('Matt', '*1*2*3*4', 'irgendeinFTP.de/', 'c:/temp/', 'Test.zip');
          END;

  }
  CODE
  {
    VAR
      HideDialog@1000000000 : Boolean;

    PROCEDURE setHideDialog@1000000002(value@1000000000 : Boolean);
    BEGIN
      HideDialog := value;
    END;

    PROCEDURE XENVIRON@1000000001(Value@1000000000 : Text[50]) : Text[1024];
    VAR
      WshShell@1000000001 : Automation "{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} 1.0:{72C24DD5-D70A-438B-8A42-98424B88AFB8}:'Windows Script Host Object Model'.WshShell";
    BEGIN
      // Webservices and RTC
      IF ISSERVICETIER THEN BEGIN
        CREATE(WshShell, TRUE, TRUE);
        EXIT( WshShell.ExpandEnvironmentStrings('%' + Value + '%') );
      END ELSE BEGIN
        EXIT( ENVIRON(Value) );
      END;
    END;

    PROCEDURE FileExists@1140002(Foldername@1140000 : Text[256]) : Boolean;
    VAR
      FileSystemObject@50000 : Automation "{420B2830-E718-11CF-893D-00A0C9054228} 1.0:{0D43FE01-F093-11CF-8940-00A0C9054228}:'Microsoft Scripting Runtime'.FileSystemObject";
    BEGIN
      IF ISCLEAR(FileSystemObject) THEN
        CREATE(FileSystemObject, TRUE, TRUE);
      EXIT(FileSystemObject.FileExists(Foldername));
    END;

    PROCEDURE getFTPData@1000000000(UsernameValue@1000000025 : Text[250];PasswordValue@1000000026 : Text[250];HostAddressValue@1000000027 : Text[1024];DestPathValue@1000000028 : Text[1024];FileNameValue@1000000029 : Text[1024]);
    VAR
      CommandsFile@1000000000 : File;
      MSShell@1000000018 : Automation "{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} 1.0:{72C24DD5-D70A-438B-8A42-98424B88AFB8}:'Windows Script Host Object Model'.WshShell";
      FileSystemObject@1000000017 : Automation "{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} 1.0:{0D43FE01-F093-11CF-8940-00A0C9054228}:'Windows Script Host Object Model'.FileSystemObject";
      WindowStyle@1000000006 : Variant;
      WaitOnReturn@1000000005 : Variant;
      DateText@1000000024 : Text[8];
      MemberNo@1000000023 : Text[6];
      HostAddress@1000000022 : Text[1024];
      CommandsFileTxt@1000000021 : Text[1024];
      FileName@1000000019 : Text[1024];
      DestinationFilePath@1000000015 : Text[1024];
      Password@1000000009 : Text[250];
      UserName@1000000008 : Text[250];
      sleepIndex@1000000004 : Integer;
      maxTimeOutMilSec@1000000003 : Integer;
      maxTimeOut@1000000002 : Integer;
      timeOut@1000000001 : Integer;
      dlg@1000000007 : Dialog;
    BEGIN
      // ###############################################################################################################################
      // Parameter
      // ###############################################################################################################################
      // Datei mit KLARTEXT Einlogg-Daten
      CommandsFileTxt := XENVIRON('TEMP') + '\__TEMP__984613516~65435164.txt';
      maxTimeOutMilSec := 60000; // 60 Sekunden Timout

      // Zugangsdaten
      UserName := UsernameValue;
      Password := PasswordValue;
      HostAddress := HostAddressValue;

      DestinationFilePath := DestPathValue;
      FileName := FileNameValue;

      // ###############################################################################################################################

      // Timeout-Berechnung
      maxTimeOut := maxTimeOutMilSec / 500;
      IF (maxTimeOutMilSec = 0) AND (maxTimeOut = 0) THEN BEGIN
        maxTimeOutMilSec := 10000;
        maxTimeOut := maxTimeOutMilSec / 500;
      END;

      IF NOT HideDialog THEN BEGIN
        dlg.OPEN('Datei wird abgerufen #1###################\'+
          'Status               #2###################\'+
          'Timeout              #3###################');

        dlg.UPDATE(1, FileName);
        dlg.UPDATE(2, 'Anfrage wird erstellt');
      END;

      IF ISCLEAR(MSShell) THEN
        CREATE(MSShell);

      IF ISCLEAR(FileSystemObject) THEN
        CREATE(FileSystemObject);

      CommandsFile.TEXTMODE(TRUE);
      CommandsFile.WRITEMODE(TRUE);

      // Wenn die Datei nicht erstellt werden kann, muss diese erst gel”st werden (noch existent)
      IF NOT CommandsFile.CREATE(CommandsFileTxt) THEN BEGIN
        // Prozess Beenden, falls noch im Zugriff
        // MSShell.ShellExecute('cmd', '/c TASKKILL /F /IM FTP.EXE /T', '', '', 0 );
        MSShell.Exec('/c TASKKILL /F /IM FTP.EXE /T');
        FileSystemObject.DeleteFile(CommandsFileTxt, TRUE);
        CommandsFile.CREATE(CommandsFileTxt)
      END;

      CommandsFile.WRITE(UserName);
      CommandsFile.WRITE(Password);
      CommandsFile.WRITE('binary');
      CommandsFile.WRITE('get ' + FileName+ ' "' + DestinationFilePath + '"' );
      CommandsFile.WRITE('quit');

      CommandsFile.TRUNC;
      CommandsFile.CLOSE;

      // MESSAGE('%1', STRSUBSTNO('ftp -s:"%1" %2', CommandsFileTxt, HostAddress));
      // ERROR('');
      // Abruf! Request!
      WindowStyle := 0; // nicht sichtbar
      WaitOnReturn := FALSE; // asynchron

      // An dieser Stelle wird die Datei aufgegriffen und mit ftp.exe verwendet
      MSShell.Run(STRSUBSTNO('ftp -s:"%1" %2', CommandsFileTxt, HostAddress), WindowStyle, WaitOnReturn);

      // wait for it! TimeOut!
      REPEAT
        IF NOT HideDialog THEN BEGIN
          // kein "flackern"
          dlg.UPDATE(2, '');
          dlg.UPDATE(2, 'Warte auf Antwort');
        END;

        SLEEP(500);
        timeOut += 1;

        IF NOT HideDialog THEN BEGIN
          // kein "flackern"
          dlg.UPDATE(3, '');
          dlg.UPDATE(3, (500 * timeOut) / 1000);
        END;

      UNTIL (FileExists(DestinationFilePath)) OR (timeOut = maxTimeOut);

      // Datei erhalten
      IF (timeOut <> maxTimeOut) THEN BEGIN
        IF NOT HideDialog THEN BEGIN
          dlg.UPDATE(2, '');
          dlg.UPDATE(2, 'Antwort erhalten!');
          // zur Darstellung
          SLEEP(1000);
        END;
      END ELSE BEGIN
      // keine Datei erhalten
        IF NOT HideDialog THEN BEGIN
          dlg.UPDATE(2, '');
          dlg.UPDATE(2, 'Antwort nicht erhalten!');
          // zur Darstellung
          SLEEP(1000);
        END;
      END;

      // Datei sicherheitshalber l”schen, Loggindaten im Klartext enthalten
      IF FileExists(CommandsFileTxt) THEN BEGIN
        // MSShell.Exec('/c TASKKILL /F /IM FTP.EXE /T');
        FileSystemObject.DeleteFile(CommandsFileTxt, TRUE);
      END;

      IF NOT HideDialog THEN
        dlg.CLOSE;
    END;

    BEGIN
    END.
  }
}

Falls sich hier der Fehlerteufel eingeschlichen hat, bitte ich um ein Kommentar 🙂

Gruß,

Matthias König

OBJECT Codeunit 50008 FTP Data
{
OBJECT-PROPERTIES
{
Date=01.09.10;
Time=12:57:38;
Modified=Yes;
Version List=;
}
PROPERTIES
{
OnRun=BEGIN
getFTPData(‚Matt‘, ‚*1*2*3*4‘, ‚irgendeinFTP.de/‘, ‚c:/temp/‘, ‚Test.zip‘);
END;}
CODE
{
VAR
HideDialog@1000000000 : Boolean;

PROCEDURE setHideDialog@1000000002(value@1000000000 : Boolean);
BEGIN
HideDialog := value;
END;

PROCEDURE XENVIRON@1000000001(Value@1000000000 : Text[50]) : Text[1024];
VAR
WshShell@1000000001 : Automation „{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} 1.0:{72C24DD5-D70A-438B-8A42-98424B88AFB8}:’Windows Script Host Object Model‘.WshShell“;
BEGIN
// Webservices and RTC
IF ISSERVICETIER THEN BEGIN
CREATE(WshShell, TRUE, TRUE);
EXIT( WshShell.ExpandEnvironmentStrings(‚%‘ + Value + ‚%‘) );
END ELSE BEGIN
EXIT( ENVIRON(Value) );
END;
END;

PROCEDURE FileExists@1140002(Foldername@1140000 : Text[256]) : Boolean;
VAR
FileSystemObject@50000 : Automation „{420B2830-E718-11CF-893D-00A0C9054228} 1.0:{0D43FE01-F093-11CF-8940-00A0C9054228}:’Microsoft Scripting Runtime‘.FileSystemObject“;
BEGIN
IF ISCLEAR(FileSystemObject) THEN
CREATE(FileSystemObject, TRUE, TRUE);
EXIT(FileSystemObject.FileExists(Foldername));
END;

PROCEDURE getFTPData@1000000000(UsernameValue@1000000025 : Text[250];PasswordValue@1000000026 : Text[250];HostAddressValue@1000000027 : Text[1024];DestPathValue@1000000028 : Text[1024];FileNameValue@1000000029 : Text[1024]);
VAR
CommandsFile@1000000000 : File;
MSShell@1000000018 : Automation „{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} 1.0:{72C24DD5-D70A-438B-8A42-98424B88AFB8}:’Windows Script Host Object Model‘.WshShell“;
FileSystemObject@1000000017 : Automation „{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} 1.0:{0D43FE01-F093-11CF-8940-00A0C9054228}:’Windows Script Host Object Model‘.FileSystemObject“;
WindowStyle@1000000006 : Variant;
WaitOnReturn@1000000005 : Variant;
DateText@1000000024 : Text[8];
MemberNo@1000000023 : Text[6];
HostAddress@1000000022 : Text[1024];
CommandsFileTxt@1000000021 : Text[1024];
FileName@1000000019 : Text[1024];
DestinationFilePath@1000000015 : Text[1024];
Password@1000000009 : Text[250];
UserName@1000000008 : Text[250];
sleepIndex@1000000004 : Integer;
maxTimeOutMilSec@1000000003 : Integer;
maxTimeOut@1000000002 : Integer;
timeOut@1000000001 : Integer;
dlg@1000000007 : Dialog;
BEGIN
// ###############################################################################################################################
// Parameter
// ###############################################################################################################################
// Datei mit KLARTEXT Einlogg-Daten
CommandsFileTxt := XENVIRON(‚TEMP‘) + ‚\__TEMP__984613516~65435164.txt‘;
maxTimeOutMilSec := 60000; // 60 Sekunden Timout

// Zugangsdaten
UserName := UsernameValue;
Password := PasswordValue;
HostAddress := HostAddressValue;

DestinationFilePath := DestPathValue;
FileName := FileNameValue;

// ###############################################################################################################################

// Timeout-Berechnung
maxTimeOut := maxTimeOutMilSec / 500;
IF (maxTimeOutMilSec = 0) AND (maxTimeOut = 0) THEN BEGIN
maxTimeOutMilSec := 10000;
maxTimeOut := maxTimeOutMilSec / 500;
END;

IF NOT HideDialog THEN BEGIN
dlg.OPEN(‚Datei wird abgerufen #1###################\’+
‚Status               #2###################\’+
‚Timeout              #3###################‘);

dlg.UPDATE(1, FileName);
dlg.UPDATE(2, ‚Anfrage wird erstellt‘);
END;

IF ISCLEAR(MSShell) THEN
CREATE(MSShell);

IF ISCLEAR(FileSystemObject) THEN
CREATE(FileSystemObject);

CommandsFile.TEXTMODE(TRUE);
CommandsFile.WRITEMODE(TRUE);

// Wenn die Datei nicht erstellt werden kann, muss diese erst gel”st werden (noch existent)
IF NOT CommandsFile.CREATE(CommandsFileTxt) THEN BEGIN
// Prozess Beenden, falls noch im Zugriff
// MSShell.ShellExecute(‚cmd‘, ‚/c TASKKILL /F /IM FTP.EXE /T‘, “, “, 0 );
MSShell.Exec(‚/c TASKKILL /F /IM FTP.EXE /T‘);
FileSystemObject.DeleteFile(CommandsFileTxt, TRUE);
CommandsFile.CREATE(CommandsFileTxt)
END;

CommandsFile.WRITE(UserName);
CommandsFile.WRITE(Password);
CommandsFile.WRITE(‚binary‘);
CommandsFile.WRITE(‚get ‚ + FileName+ ‚ „‚ + DestinationFilePath + ‚“‚ );
CommandsFile.WRITE(‚quit‘);

CommandsFile.TRUNC;
CommandsFile.CLOSE;

// MESSAGE(‚%1‘, STRSUBSTNO(‚ftp -s:“%1″ %2‘, CommandsFileTxt, HostAddress));
// ERROR(“);
// Abruf! Request!
WindowStyle := 0; // nicht sichtbar
WaitOnReturn := FALSE; // asynchron

// An dieser Stelle wird die Datei aufgegriffen und mit ftp.exe verwendet
MSShell.Run(STRSUBSTNO(‚ftp -s:“%1″ %2‘, CommandsFileTxt, HostAddress), WindowStyle, WaitOnReturn);

// wait for it! TimeOut!
REPEAT
IF NOT HideDialog THEN BEGIN
// kein „flackern“
dlg.UPDATE(2, “);
dlg.UPDATE(2, ‚Warte auf Antwort‘);
END;

SLEEP(500);
timeOut += 1;

IF NOT HideDialog THEN BEGIN
// kein „flackern“
dlg.UPDATE(3, “);
dlg.UPDATE(3, (500 * timeOut) / 1000);
END;

UNTIL (FileExists(DestinationFilePath)) OR (timeOut = maxTimeOut);

// Datei erhalten
IF (timeOut <> maxTimeOut) THEN BEGIN
IF NOT HideDialog THEN BEGIN
dlg.UPDATE(2, “);
dlg.UPDATE(2, ‚Antwort erhalten!‘);
// zur Darstellung
SLEEP(1000);
END;
END ELSE BEGIN
// keine Datei erhalten
IF NOT HideDialog THEN BEGIN
dlg.UPDATE(2, “);
dlg.UPDATE(2, ‚Antwort nicht erhalten!‘);
// zur Darstellung
SLEEP(1000);
END;
END;

// Datei sicherheitshalber l”schen, Loggindaten im Klartext enthalten
IF FileExists(CommandsFileTxt) THEN BEGIN
// MSShell.Exec(‚/c TASKKILL /F /IM FTP.EXE /T‘);
FileSystemObject.DeleteFile(CommandsFileTxt, TRUE);
END;

IF NOT HideDialog THEN
dlg.CLOSE;
END;

BEGIN
END.
}
}

Kommentare
  1. Bernd sagt:

    Merci!
    Da war nur ein kleiner Tacken mit „MSShell.Run“ der mir schon der ganze Zeit fehlte…

  2. Appreciate the recommendation. Will try it out.

  3. After I originally commented I seem to have clicked
    the -Notify me when new comments are added- checkbox and
    now each time a comment is added I recieve 4 emails
    with the same comment. There has to be an easy method you
    can remove me from that service? Appreciate it!

Hinterlasse einen Kommentar