web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Suggested Answer

Upload all files where filename starts with po_ from ftp

(0) ShareShare
ReportReport
Posted on by 235

This question is 3 fold.   I have a ftp site Folder structure is …/importfolder/     Which contains 2 more folders …/importfolder/success/  and …/importfolder/failure/.   I have a requirement where I need to download(import) .csv files where the name starts with "po_" from the …/importfolder/ on the ftp site.  example po_1.csv, or po_123.csv.  Once I have downloaded and processed (I write the content to a table) it I need to move it to the success folder indicating it has been downloaded successfully, or if it could not be downloaded it must be moved to the  â€¦/importfolder/failure/ folder.   I am able to download and process the file when I give it a specific name

  1. How would I indicate the filename with a like "FtpWebRequest       request = WebRequest::Create("ftp://****/importfolder/po_*.csv");
  2. How would I read file by file to ensure that I read and process all the files whose name start with po_ .
  3. How would I move the file that has been read to a different folder.

This is the code that I am currently using and it works fine for a specific file name.  Please if someone can assist I would so appreciate it.

public static Boolean downloadFile(str _filename)
{
     newFilePO      orderFile;
     str            orderId, item;
     container      line;
     int      rec;
     ReqRefType     refType;
     CommaTextStreamIo   commaTextStreamIo;
     System.Byte[]       buffer = new System.Byte[10240]();
     System.IO.Stream    fileStream = new System.IO.MemoryStream();
     str                 targetFile = System.IO.Path::GetRandomFileName();
     FtpWebRequest       request = WebRequest::Create("ftp://**********/importfolder/po_3.csv");
  
     request.Credentials = new NetworkCredential("*USER*","*Password*");
     commaTextStreamIo = commaTextStreamIo::constructForRead(fileStream);
 
     commaTextStreamIo.inFieldDelimiter(',');
     commaTextStreamIo.inRecordDelimiter('\n');
     line = commaTextStreamIo.read();       //Header row
     line = commaTextStreamIo.read();       //First row
     ttsbegin;
     while(line)
     {
      orderId = conpeek(line, 2);
      item    = conpeek(line, 4);
      //Skip if order already exists on table
      if(!newFilePO::find(orderId,item,false))
      {
       orderFile.initValue();
       orderFile.OrderID       = orderId;   //2
       orderFile.DueDate      = conPeek(line, 3);
       orderFile.Item          = item;      //4
       orderFile.insert();
      }
      line = commaTextStreamIo.read();
     }
     ttscommit;
     return true;
}

Any advice will be much appreciated

I have the same question (0)
  • Suggested answer
    Martin Dráb Profile Picture
    237,795 Most Valuable Professional on at

    1. How to: List directory contents with FTP shows how to list files using FtpWebRequest (although you might find out that the result isn't exactly what you want…).

    2. Simply iterate files one by one. You already know how to handle a single file.

    3. For moving, try code like this:

    request.Method = WebRequestMethods.Ftp::Rename;
    request.RenameTo = "/failure/file.xml";

  • Sophia.r Profile Picture
    235 on at

    Hi Martin Thank you for your prompt response.  But with this link  like so many others I have tried I keep getting errors just trying to write the code.  As If I am missing a reference.  I have now tried to create a runnable class so that I can replicate this code, the intellisense allows me to select but on the last WebRequest it indicates it is expecting ;  so I cant even type the code in as the page indicates

    using System;

    using System.IO;

    using System.Net;

    class PBFJobTestFtp

    {        

       /// <summary>

       /// Runs the class with the specified arguments.

       /// </summary>

       /// <param name = "_args">The specified arguments.</param>

       public static void main(Args _args)

       {      

           FtpWebRequest request = (FtpWebRequest)WebRequest.Create("");

       }

    }

    Am I using wrong code for Dynamics 365 Finance and Operations?  The same occurred for the following code.

    In this case the code builds but when I run the code I get an (NotSupportedException was unhandled by user code : The given path's format is not supported.  I am sure the path should be fine as I can ctrl Select on the path that I typed in and it opens up the correct folder.

    System.String[] filePaths = System.IO.Directory::GetFiles(@"folder location", "*.*", System.IO.SearchOption::AllDirectories); //get listing of all files within the folder

       int fileCount = filepaths.get_Length(); //get how many files were found

       int currentFileCount;

       //go throw each one of the files that were found

       for(currentFileCount = 0; currentFileCount < fileCount ; ++currentFileCount)

       {

           info(filepaths.GetValue(currentFileCount));

       }

  • Suggested answer
    Sukrut Parab Profile Picture
    71,710 Moderator on at

    You can also use SSH.net library . Once you create sftp client , you cna call list file method to  list all the files in a directory. Refer below link for example.

    ourcodeworld.com/.../how-to-access-a-sftp-server-using-ssh-net-sync-and-async-with-c-in-winforms

  • Martin Dráb Profile Picture
    237,795 Most Valuable Professional on at

    Your code above isn't valid in X - you've copied a piece of C# code and you're trying to compile it as X , which (usually) won't work.

    This C# code

    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(url);

    can be written in X like this:

    FtpWebRequest request = WebRequest::Create(url);

    X doesn't support C# syntax for casting (e.g. (FtpWebRequst)o) and it uses :: to call static methods.

  • Sophia.r Profile Picture
    235 on at

    Thanks Martin How would I then write

    request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;    in x++.  That is my requirement.  To create a loop of files found in the directory and process them 1 by 1 in x++.  Somehow all the solutions I find while investigating are not for x++

  • Martin Dráb Profile Picture
    237,795 Most Valuable Professional on at

    Of course most solutions using .NET APIs are not for X++. Languages such as C# and Visual Basic .NET are used by may times more people than X++.

    If you want to be able to use C# code you find, you can. Instead of re-writing everything to X++, create a C# library, implement the whole logic in C# and then call the library from X++. That may be a single method call from X++.

    You can do that by adding a C# code library project to the solution with your X++ project, building the C# project and then adding a project reference to your X++ project.

  • Martin Dráb Profile Picture
    237,795 Most Valuable Professional on at

    WebRequestMethods.Ftp is an nested class and (AFAIK) there is no support for them in .NET Interop from X++, therefore using them isn't easy. I recommend you do it in C#, as discussed in the previous reply.

  • Sophia.r Profile Picture
    235 on at

    Hi Martin I am having some progress, but I still have a issue using C# library.

    I have created C# Library and also tested the code from a different C# project so I know the code is working.(Returning the correct results)  I have added the library as reference to my X++ Project and also added it with Using in my class(Not sure if this is necessary)  However when I try to call my method it does not find it and gives an error "Method 'getFileList() is not found on type "PBFCListDirectory.FtpList). What can I have missed here?.  When I type, intellisense picks up the Namespace and the class but then does not pick up the method.

    Am I calling the method correctly from X++?

    //using PBFCListDirectory;

    class PBFJobTestFtp

    {        

       /// <summary>

       /// Runs the class with the specified arguments.

       /// </summary>

       /// <param name = "_args">The specified arguments.</param>

       public static void main(Args _args)

       {      

           DMFParameters   dmfParameter;

           List            fileList = new List(Types::String);

           ListIterator    iterator;

           str             dwnldFile;

           boolean         success;

           PBFCListDirectory.FtpList ftpList = new PBFCListDirectory.FtpList();

           dmfParameter    = DMFParameters::find();

           fileList = ftpList.getFileList('server','folder','User','Password');  //error on this line

           iterator = new ListIterator(fileList);

           while(iterator.more())

           {

               dwnldFile = iterator.value();

               success = PBFAzureStorageControl::downloadFile(dwnldFile);

               ftpList.movefile('server','folder','User','Password',dwnldFile, success); //error on this line

               iterator.next();

           }

       }

    }

    Below is the moveFile method.  I tried it with the static and without

    public static void moveFile(String Server, String from_Netstock, String UserId, String Password, string nameImport, bool success)

    {

    string filePathTo = null;

    FtpWebRequest ftpRequest = null;

    FtpWebResponse ftpResponse = null;

    if (success == true)

    {

    filePathTo = "success/" + nameImport;

    }

    else

    {

    filePathTo = "failure/" + nameImport;

    }

    try

    {

    ftpRequest = (FtpWebRequest)WebRequest.Create("ftp://" + Server + "/" + from_Netstock + "/" + nameImport);

    ftpRequest.Credentials = new NetworkCredential(UserId, Password);

    ftpRequest.UseBinary = true;

    ftpRequest.UsePassive = true;

    ftpRequest.KeepAlive = true;

    ftpRequest.Method = WebRequestMethods.Ftp.Rename;

    ftpRequest.RenameTo = filePathTo;

    ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();

    ftpResponse.Close();

    ftpRequest = null;

    }

    catch (WebException e )

    {

    string status = ((FtpWebResponse)e.Response).StatusDescription;

    }

    }

  • nmaenpaa Profile Picture
    101,160 Moderator on at

    Could you share the getFileList method of your C# class?

  • Sophia.r Profile Picture
    235 on at

    Hi Nikolaos following is the method getFileList.  I hope you can help me with this.

    This method I removed the static to test from C# project and to see if it influenced the availability of the methoin any way.

    public String[] getFileList(String Server, String from_Netstock, String UserId, String Password)

    {

    string[]        downloadFiles = null;

    StringBuilder   result = new StringBuilder();

    FtpWebRequest   reqFTP = null;

    StreamReader    reader = null;

    WebResponse     response = null;

    String          FilesListing = "";

    String          Last = "";

    try

    {

    reqFTP = (FtpWebRequest)FtpWebRequest.Create("ftp://" + Server + "/" + from_Netstock);

    reqFTP.Credentials = new NetworkCredential(UserId, Password);

    reqFTP.Method = WebRequestMethods.Ftp.ListDirectoryDetails;

    reqFTP.KeepAlive = false;

    reqFTP.Timeout = 10000;

    response = reqFTP.GetResponse();

    reader = new StreamReader(response.GetResponseStream(), System.Text.Encoding.ASCII);

    string line = reader.ReadLine();

    while (line != null)

    {

    result.Append(line);

    result.Append("\n");

    line = reader.ReadLine();

    }

    if (result.ToString().Trim().Length > 1)

    {

    result.Remove(result.ToString().LastIndexOf('\n'), 1);

    }

    downloadFiles = result.ToString().Split('\n');

    DateTime Lowest = DateTime.Now;

    foreach (string strline in downloadFiles)

    {

    if (strline.Trim() != "" && (!strline.ToString().ToLower().Trim().StartsWith("total")) && (!strline.ToString().ToLower().Trim().StartsWith("d")))

    {

    if(strline.Contains("po_") || strline.Contains("trans_"))

    {

    FilesListing += strline.Substring(39) + ";";

    }

    }

    }

    return FilesListing.Split(';');

    }

    catch

    {

    return (Last).Split(';');

    }

    finally

    {

    reader.Close();

    reader.Dispose();

    response.Close();

    }

    }

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Neeraj Kumar – Community Spotlight

We are honored to recognize Neeraj Kumar as our Community Spotlight honoree for…

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
Martin Dráb Profile Picture

Martin Dráb 660 Most Valuable Professional

#2
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 549 Super User 2025 Season 2

#3
Sohaib Cheema Profile Picture

Sohaib Cheema 307 User Group Leader

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans