Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read file from FTP to memory in C#

I want to read a file from a FTP server without downloading it to a local file. I wrote a function but it does not work:

private string GetServerVersion()
{
    WebClient request = new WebClient();

    string url = FtpPath + FileName;
    string version = "";

    request.Credentials = new NetworkCredential(ftp_user, ftp_pas);

    try
    {
        byte[] newFileData = request.DownloadData(new Uri(FtpPath)+FileName);
        string fileString = System.Text.Encoding.UTF8.GetString(newFileData);
    }
    catch (WebException e)
    {
    }
    return version;
}
like image 868
Mselmi Ali Avatar asked May 23 '11 14:05

Mselmi Ali


2 Answers

Here's a simple working example using your code to grab a file from the Microsoft public FTP servers:

WebClient request = new WebClient();
string url = "ftp://ftp.microsoft.com/developr/fortran/" +"README.TXT";
request.Credentials = new NetworkCredential("anonymous", "[email protected]");

try
{
  byte[] newFileData = request.DownloadData(url);
  string fileString = System.Text.Encoding.UTF8.GetString(newFileData);
  Console.WriteLine(fileString);
}
catch (WebException e)
{
  // Do something such as log error, but this is based on OP's original code
  // so for now we do nothing.
}

I reckon you're missing a slash on this line here in your code:

string url = FtpPath + FileName;

Perhaps between FtpPath and FileName ?

like image 75
Kev Avatar answered Sep 20 '22 17:09

Kev


Small binary file

If the file is small, the easiest way is using WebClient.DownloadData:

WebClient client = new WebClient();
string url = "ftp://ftp.example.com/remote/path/file.zip";
client.Credentials = new NetworkCredential("username", "password");
byte[] contents = client.DownloadData(url);

Small text file

If the small file is a text file, use WebClient.DownloadString:

string contents = client.DownloadString(url);

It assumes that the file contents is in UTF-8 encoding (a plain ASCII file will do too). If you need to use a different encoding, use WebClient.Encoding property.


Large binary file

If the file is large, so that you need to process it in chunks, instead of loading it to memory whole, use FtpWebRequest:

FtpWebRequest request =
    (FtpWebRequest)WebRequest.Create("ftp://ftp.example.com/remote/path/file.zip");
request.Credentials = new NetworkCredential("username", "password");
request.Method = WebRequestMethods.Ftp.DownloadFile;

using (Stream stream = request.GetResponse().GetResponseStream())
{
    byte[] buffer = new byte[10240];
    int read;
    while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
    {
        // process the chunk in "buffer"
    }
}

You can also simplify the code by using WebClient.OpenRead.


Large text file

If the large file is a text file and you want to process it by lines, instead of by chunks of a fixed size, use StreamReader:

FtpWebRequest request =
    (FtpWebRequest)WebRequest.Create("ftp://ftp.example.com/remote/path/file.txt");
request.Credentials = new NetworkCredential("username", "password");
request.Method = WebRequestMethods.Ftp.DownloadFile;

using (Stream stream = request.GetResponse().GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
    while (!reader.EndOfStream)
    {
        string line = reader.ReadLine();
        // process the line
        Console.WriteLine(line);
    }
}

Again, this assumes UTF-8 encoding. If you want to use another encoding, use an overload of StreamReader constructor that takes also Encoding.

As previously, you can simplify the code by using WebClient.OpenRead.


Stream interface

Though, in many cases, you will want to use the downloaded data in some API that uses the Stream interface. In that case, instead of using any of the solutions above, directly use the stream returned by request.GetResponse().GetResponseStream() or WebClient.OpenRead in the API.

For an example, see Transferring files from FTP directly to Azure Blob storage in C#.

like image 41
Martin Prikryl Avatar answered Sep 21 '22 17:09

Martin Prikryl