Click here to Skip to main content
15,889,315 members
Articles / Programming Languages / C#
Article

FTP component written with fully managed code

Rate me:
Please Sign up or sign in to vote.
4.78/5 (61 votes)
7 May 20021 min read 861.7K   14.7K   178   251
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

C#
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

C#
/*
* 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

C#
session.CurrentDirectory = somesubdirectory

Upload file

C#
//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

C#
//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

C#
//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

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

Delete a subdirectory

C#
//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

C#
/*
* 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

C#
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


Written By
Web Developer
Hong Kong Hong Kong
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralParent directory Pin
Anonymous20-Oct-02 22:09
Anonymous20-Oct-02 22:09 
Generalanonymous connection not accepted Pin
nenhel13-Sep-02 12:13
nenhel13-Sep-02 12:13 
GeneralFailed to open data connection Pin
Rogerw13-Sep-02 2:10
Rogerw13-Sep-02 2:10 
GeneralRe: Failed to open data connection Pin
Fantasier8-Jul-03 9:55
Fantasier8-Jul-03 9:55 
General"price is really too high for poor men like me" Pin
sbc1111-Sep-02 15:17
sbc1111-Sep-02 15:17 
GeneralThis is great... but Pin
Anonymous29-Aug-02 7:48
Anonymous29-Aug-02 7:48 
Generalread only Pin
romain20-Aug-02 0:21
romain20-Aug-02 0:21 
GeneralCan't find the bug :) Pin
17-Aug-02 2:22
suss17-Aug-02 2:22 
Hi there,
first thank U for this great and useful work! I was planning to implement my own ftp control, but you've done the job Wink | ;)

Well, i've a little problem with the component:
I use It with BulletProof FTP Server (g6) available at http://www.bpftpserver.com/
First, there was a problem with the listdir regexp, but now It's fixed (OK with the third unix regex you gave here in the forum)

My bug is that the module randomly freezes after LIST command.
In fact there's a blocking call to ReadAppendChar ( read blocking -> char c = (char)r.Read();) but i don't know why !!!
It's very strange...

Here is my FTPD log:
227 Entering Passive Mode (127,0,0,1,173,65).
LIST
150 Data connection accepted from 127.0.0.1:1112; transfer starting.
226 Transfer ok



in fact the last working getline returns the "150 Data connection accepted from 127.0.0.1:1112; transfer starting." line OK, but the next getline call (wich should get "226 Transfer ok") is blocking... I just don't understand this behaviour, because the ftpd send the 226 line, so why does the client can't read it, and is blocked ????
THE FUNNY THING is that the problem DON'T APPEAR ALL THE time! sometimes it works OK, and sometimes NOT (as the FTPD log is still the SAME!!!)
The DataConnection is OK and I get the LIST content without any problem...
So what's wrong? any delay problem? (as the ftpd is localhost, maybe too fast? but event in step by step debug mode, it's freezing)

Last thing, the functions calling stack is as it:
kcommon.dll -> FTPResponse.ReadAppendChar
kcommon.dll -> FTPResponse.Getline
kcommon.dll -> FTPResponse() constructor
kcommon.dll -> ControlChannel.RefreshResponse
kcommon.dll -> FTPDataStream.Close()
mscorlib.dll -> StreamReader::Dispose
mscorlib.dll -> StreamReader::Close
kcommon.dll -> ControlChannel.List

AND if I suppress these lines in the List() method :
lineReader.Close();

if(m_lastResponse.Code != FtpResponse.ClosingDataChannel)
throw new FtpException(errorMsgListing, m_lastResponse);
THEN It's working (ignoring the 226 recv) : But It's not a solution to comment out these 3 lines...

I don't understand the problem at all (ok ok, i haven't read all your module code....), could You help me pliz Alex !!!!!
Could it be a lock() problem? a socket delay problem? why the hell the Getline method can't get its 226 line!?????? and why the hell this is sometime working (with exactly the same behaviour in the client AND server) ?

Dead | X| Unsure | :~ Confused | :confused: pliz pliz pliz help help help Eek! | :eek: Eek! | :eek: Eek! | :eek:

Thanx in advance and sorry for my poor english level...

Julien WTF | :WTF:
GeneralRe: Can't find the bug :) Pin
Ratounet17-Aug-02 2:36
Ratounet17-Aug-02 2:36 
GeneralRe: Can't find the bug :) Pin
Dominik Steiner21-Aug-02 1:54
Dominik Steiner21-Aug-02 1:54 
GeneralRe: Can't find the bug :) Pin
liangxs11-Mar-03 22:42
liangxs11-Mar-03 22:42 
GeneralRe: Can't find the bug :) Pin
Alex Kwok12-Mar-03 16:28
Alex Kwok12-Mar-03 16:28 
QuestionSimultaneous Downloads? Pin
Matt Philmon1-Aug-02 10:20
Matt Philmon1-Aug-02 10:20 
AnswerRe: Simultaneous Downloads? Pin
Alex Kwok2-Aug-02 4:55
Alex Kwok2-Aug-02 4:55 
GeneralRe: Simultaneous Downloads? Pin
Matt Philmon5-Aug-02 5:01
Matt Philmon5-Aug-02 5:01 
GeneralRe: Simultaneous Downloads? Pin
Jason Gerard22-Aug-02 3:28
Jason Gerard22-Aug-02 3:28 
GeneralRe: Simultaneous Downloads? Pin
Jon Rista26-Nov-02 16:21
Jon Rista26-Nov-02 16:21 
GeneralRe: Simultaneous Downloads? Pin
Matt Philmon26-Nov-02 16:35
Matt Philmon26-Nov-02 16:35 
GeneralRe: Simultaneous Downloads? Pin
Alex Kwok13-Aug-02 18:33
Alex Kwok13-Aug-02 18:33 
GeneralGeneral Help Pin
OnuSigep19-Jul-02 10:05
OnuSigep19-Jul-02 10:05 
GeneralRe: General Help Pin
Anonymous9-Aug-02 6:24
Anonymous9-Aug-02 6:24 
GeneralRe: General Help Pin
Matt Philmon13-Aug-02 18:28
Matt Philmon13-Aug-02 18:28 
GeneralRe: General Help Pin
Anonymous13-Nov-02 23:41
Anonymous13-Nov-02 23:41 
GeneralLicensing Pin
Scott Hernandez18-Jul-02 7:49
Scott Hernandez18-Jul-02 7:49 
GeneralRe: Licensing Pin
Alex Kwok18-Jul-02 21:23
Alex Kwok18-Jul-02 21:23 

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

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