How to upload a file to an FTP server using C#?

C# (Mono) on FreeBSD

Ok, so today I needed to FTP a file.  It took me some time and research but I have a function that will upload a file to an FTP server.

I found a lot of examples that were very complex, and rightfully so as they have a lot of error and exception handling. However, this complexity makes it difficult to learn.

So this is a non-complex version. It follows some basic steps:

  1. Get the local file name: C:\Users\Rhyous\Desktop\File1.zip
  2. Open a request using the full destination ftp path: Ftp://Ftp.Server.tld/Path/File1.zip
  3. Configure the connection request
  4. Create a stream from the file
  5. Read the file into the a local stream
  6. Close the local stream
  7. Create a stream to the FTP server
  8. Write the local stream to the FTP stream
  9. Close the stream to the FTP server
using System;
using System.IO;
using System.Net;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
			string ftplocation = "ftp://ftp.server.tld/path";
			string file = @"C:\Users\Rhyous\Desktop\File1.zip" // Or on FreeBSD: "/usr/home/jared/test2.txt";
			string user = "Anonymous";
			string password = "AnyPasswd!";
            UploadToFTP(ftplocation, file, user, password);
        }

        static void UploadToFTP(String inFTPServerAndPath, String inFullPathToLocalFile, String inUsername, String inPassword)
        {
            // Get the local file name: C:\Users\Rhyous\Desktop\File1.zip
            // and get just the filename: File1.zip. This is so we can add it
            // to the full URI.
            String filename = Path.GetFileName(inFullPathToLocalFile);

            // Open a request using the full URI, c/file.ext
            FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(inFTPServerAndPath + "/" + filename);

            // Configure the connection request
            request.Method = WebRequestMethods.Ftp.UploadFile;
            request.Credentials = new NetworkCredential(inUsername, inPassword);
            request.UsePassive = true;
            request.UseBinary = true;
            request.KeepAlive = false;

            // Create a stream from the file
            FileStream stream = File.OpenRead(inFullPathToLocalFile);
            byte[] buffer = new byte[stream.Length];

            // Read the file into the a local stream
            stream.Read(buffer, 0, buffer.Length);

            // Close the local stream
            stream.Close();

            // Create a stream to the FTP server
            Stream reqStream = request.GetRequestStream();

            // Write the local stream to the FTP stream
            // 2 bytes at a time
            int offset = 0;
            int chunk = (buffer.Length > 2048) ? 2048 : buffer.Length;
            while (offset < buffer.Length)
            {
                reqStream.Write(buffer, offset, chunk);
                offset += chunk;
                chunk = (buffer.Length - offset < chunk) ? (buffer.Length - offset) : chunk;
            }
            // Close the stream to the FTP server
            reqStream.Close();
        }
    }
}

This works well for most files.

One problem is that this code reads the entire local file into memory, which might not be a good idea for a file that is very large (multiple gigabytes). It would be better to read the local file in bits. I upload in bits so this would not be hard to read a little bit, upload it, read a little bit more, upload it, etc…

Resources:
http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.aspx
http://msdn.microsoft.com/en-us/library/system.io.stream.aspx
http://www.vcskicks.com/csharp_ftp_upload.php