Click here to Skip to main content
Licence 
First Posted 7 May 2002
Views 542,283
Bookmarked 168 times

FTP component written with fully managed code

By | 7 May 2002 | Article
A .NET FTP component

Recently, I needed to write a program which could automatically download files from an FTP server. Unfortunately the .NET Framework lacks good support for FTP services. Although a few companies have already written libraries which can be used directly, the price is really too high for poor men like me. As a result, I decided to write my own FTP library and here it is.

Disclaimer

This FTP component is an incomplete implementation of my design nor has it been fully tested. Please keep in mind it may contain bugs or even design flaws.

Connect to FTP server

FtpSession session = new FtpSession();
session.Server = "localhost";
session.Port   = 21; //not required if using the default ftp port 21
session.Connect("anonymous", "someone@somewhere.com");

Enum subdirectories and files

/*
* It is possible an incorrect list will be returned.
* In this case, you need to add your own regular expression to 
* interpret the list result (try to find it within ftpdirectory.cs)
*/
FtpDirectory root = session.RootDirectory;
foreach(FtpDirectory d in root.SubDirectories)
    //do something

    foreach(FtpFile f in root.Files)
        //do something

        /*
         * Only CurrentDirectory's item can be legally used.
         * Do not save down FtpDirectory and FtpFile for later use
         * unless you are sure they belongs to CurrentDirectory.
         * Here is some sample may cause problems
         */
        FtpDirectory d1 = session.CurrentDirectory.FindSubdirectory("somesubdir");
        FtpDirectory d2 = session.CurrentDirectory.FindSubdirectory("othersubdir");
        session.CurrentDirectory = d2;
        
        /*
         * Following 2 line will cause problem since CurrentDirectory 
         * is not d1's parent anymore
         */
        foreach(FtpDirectory d in d1) 
            //dosomthing

Change current directory

session.CurrentDirectory = somesubdirectory

Upload file

//Blocking call
session.CurrentDirectory.PutFile("somelocalfile");
    
//Async call using callback
session.CurrentDirectory.BeginPutFile("somelocalfile", +
    new FtpAsyncDelegate(yourcallback);
    
//Async call using event
session.EndPutFile += new FtpFileEventHandler(yourhandler);
session.CurrectDirectory.BeginPutFile("somelocalfile");
        
    //Manually upload the file
    FileInfo fi = new FileInfo(localfilefullpath);
    Stream r = File.OpenRead(fi.FullName);

    // actually will return a FtpOutputDataStream object
    Stream w = session.CurrentDirectory.CreateDataStream(fi.Name); 
    int readed;
    byte[] buff = new byte[4096];
    while((readed=r.Read(buff, 0, 4096) != 0)
	    w.Write(buff, 0, readed);
    /*
    * Must call FtpDataStream.Close().
    * This is because it will try to read the file transfer 
    * result from FTP server.
    */
    w.Close();
    s.Close();

Download file

//Blocking call
session.CurrentDirectory.GetFile("someremotefile");
    
//Async call using callback
session.CurrentDirectory.BeginGetFile("someremotefile", + 
    new FtpAsyncDelegate(yourcallback);
    
//Async call using event
session.EngGetFile += new FtpFileEventHandler(yourhandler);
session.CurrectDirectory.BeginGetFile("someremotefile");

//Manually download a file
Stream r = File.OpenWrite(localfilepath);

    FtpFile remoteFile = session.CurrentDirectory.FindFile(remotefilename);
    Stream w = remoteFile.GetOutputDataStream();
    int readed;
    byte[] buff = new byte[4096];
    while((readed=r.Read(buff, 0, 4096) != 0)
        w.Write(buff, 0, readed);
    /*
    * Must call FtpDataStream.Close().
    * This is because it will try to read the file transfer 
    * result from FTP server.
    */
    w.Close();
    s.Close();

Create a new file in ftp server

//method 1
session.CurrentDirectory.CreateFile(newfilename);
        
//method 2
Stream s = session.CurrentDirectory.CreateFileStream(newfilename);
// do something with s
s.Close();

Delete a file from ftp server

//method 1
session.CurrentDirectory.RemoveFile(remotefilename);
        
//method 2
IFtpItem item = session.CurrentDirectory.FindItem(remotefilename)
if(item != null)
    session.CurrentDirectory.RemoveItem(item);

Delete a subdirectory

//method 1
session.CurrentDirectory.RemoveSubdir(subdirectoryname);

//method 2
IFtpItem item = session.CurrentDirectory.FindItem(sub directoryname)
if(item != null)
    session.CurrentDirectory.RemoveItem(item);

Refresh the content of ftp directory

/*
* If you have saved down some some directory item(subdir or ftpfile).
* They will become invalid after you refresh the directory
*/
FtpFile f = session.CurrentDirectory.FindFile(somefile);
         
// you can not leagally use f anymore after the following line
session.CurrentDirectory.Refresh();

Rename a file or directory

IFtpItem item = session.FindItem(directoryorfile);
if(item != null)
    session.RenameSubitem(item, newname);

Known Limitations

  • No support for active mode
  • No support for proxy server

Updates

  • Removed FileCollection and DirectoryCollection
  • Added support for VB's for each statement
  • VB client can directly access FtpDirectory.Files and FtpDirectory.SubDirectories with for each statement now.

Please send me a email if you find any bugs. Please include at least a description of the bug you have found. It will be nice if a testing program or even a solution is included.

Have fun.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Alex Kwok

Web Developer

Hong Kong Hong Kong

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
AnswerRe: kcommon.dll Pinmember_anagram_6:12 1 Nov '06  
QuestionRe: kcommon.dll Pinmemberalexander_z214:38 12 Jul '11  
QuestionHow to download from ftp server using VS2003 PinmemberRaju Sharma20:21 17 Oct '06  
Generalftp upload Pinmemberpreets30820:15 16 Jul '06  
GeneralCoping file to different directory in remote server Pinmemberjasocl22:11 3 Jul '06  
AnswerRe: Coping file to different directory in remote server Pinmemberstixoffire5:18 10 Apr '08  
GeneralUNIX regex's not recognising all files returned by LIST command - fix supplied here!! PinmemberStewart Rae15:58 8 May '06  
Great component Alex - awesome work!! Smile | :)
 
I noticed that the UNIX regex's were failing to recognise some files and directories that were returned by the FTP server, specifically the following patterns weren't being matched in MatchingListLine()
 
-rw-r--r--   1 500         500            251805 May   3 16:53 filename.txt
drwxr-xr-x   7 root      root            4096 Apr 11 15:47 dirname
 

Here's the fix - in FtpDirectory change implement the following 4 regex's:
 
#region Regular expression to parse list lines
static Regex m_UnixListLineExpression1 = new Regex(@"(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{4})\s+(?<name>.+)");
static Regex m_UnixListLineExpression2 = new Regex(@"(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{2}:\d{2})\s+(?<name>.+)");
static Regex m_UnixListLineExpression3 = new Regex(@"(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{4})\s+(?<name>.+)");
static Regex m_UnixListLineExpression4 = new Regex(@"(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{2}:\d{2})\s+(?<name>.+)");
static Regex m_DosListLineExpression   = new Regex(@"(?<timestamp>\d{2}\-\d{2}\-\d{2}\s+\d{2}:\d{2}[Aa|Pp][mM])\s+(?<dir>\<\w+\>){0,1}(?<size>\d+){0,1}\s+(?<name>.+)");
#endregion
 

... and modify MatchingListLine as follows:
 
private Match MatchingListLine(string line)
{
      Match m = m_UnixListLineExpression1.Match(line);
      if(m.Success)
            return m;
      m = m_UnixListLineExpression2.Match(line);
      if(m.Success)
            return m;
      m = m_UnixListLineExpression3.Match(line);
      if(m.Success)
            return m;
      m = m_UnixListLineExpression4.Match(line);
      if(m.Success)
            return m;
      m = m_DosListLineExpression.Match(line);    
      if(m.Success)
            return m;
 
      return null;
}
 

Also, the working directory after logging in to an FTP server may not be the user's root - it may be possible to navigate up past it.   The following code change allows the user to do this using FtpDirectory.Parent
 
public FtpDirectory Parent
{
      get
      {
            CheckSessionCurrentDirectory();
            //if(m_fullPath == m_session.RootDirectory.m_fullPath)
            //   return null;
            if(m_fullPath == "/")
                  return null;
 
            <...snip...>
 
            return parent;
      }
}
 
Thanks Smile | :)
GeneralRe: UNIX regex's not recognising all files returned by LIST command - fix supplied here!! PinmemberShorin_gr4:14 15 Jun '06  
GeneralRe: UNIX regex's not recognising all files returned by LIST command - fix supplied here!! PinmemberAquaJo9:14 13 Jul '06  
GeneralRe: UNIX regex's not recognising all files returned by LIST command - fix supplied here!! Pinmemberjosias_c9:20 28 Oct '10  
GeneralRe: UNIX regex's not recognising all files returned by LIST command - fix supplied here!! Pinmemberlesnikowski7:39 4 Jan '11  
GeneralCannot connect .. Help !! PinmemberStar999917:18 19 Apr '06  
GeneralSubdirectory Pinmembernmbvc5:01 2 Mar '06  
GeneralRe: Subdirectory Pinmembertherearefartoomanybens14:51 13 Dec '09  
Questioncan't download demo file? PinsussAnonymous13:39 6 Oct '05  
GeneralHi Alex Pinmembersantosh poojari20:40 14 Sep '05  
GeneralHelp!! Problem Kcommon GetFile PinmemberJugkrit_Emp@hotmail.com21:07 22 Aug '05  
GeneralRe: Help!! Problem Kcommon GetFile PinsussAnonymous0:58 29 Aug '05  
Generalavoid blocking while reading response stream! Pinmember[pascal]4:59 17 Aug '05  
GeneralRe: avoid blocking while reading response stream! Pinmembercphexad3:44 13 Feb '07  
GeneralHi Help needed PinmemberNR_gopal1:40 3 Aug '05  
Generalunhandled exceptions Pinmember[pascal]6:24 27 Jul '05  
Generalpatch for linux ftp list parsing Pinmember[pascal]5:57 25 Jul '05  
GeneralRe: patch for linux ftp list parsing Pinmembercwetzelberger4:41 8 May '07  
Generaluploading images to ftp using files Pinmemberv.venkannababu23:44 4 Jun '05  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120529.1 | Last Updated 8 May 2002
Article Copyright 2002 by Alex Kwok
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid