How to Download Zip file from Ftp in C# - c#

I have to download zip file from ftp using c# code.
i have used the following code.
Uri url = new Uri("ftp://ftpurl");
if (url.Scheme == Uri.UriSchemeFtp)
{
FtpWebRequest objRequest = (FtpWebRequest)FtpWebRequest.Create(url);
//Set credentials if required else comment this Credential code
NetworkCredential objCredential = new NetworkCredential(userid, Pwd);
objRequest.Credentials = objCredential;
objRequest.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponse objResponse = (FtpWebResponse)objRequest.GetResponse();
StreamReader objReader = new StreamReader(objResponse.GetResponseStream());
byte[] buffer = new byte[16 * 1024];
int len = 0;
FileStream objFS = new FileStream(#"E:\ftpwrite", FileMode.Create, FileAccess.Write, FileShare.Read);
while ((len = objReader.BaseStream.Read(buffer, 0, buffer.Length)) != 0)
{
objFS.Write(buffer, 0, len);
}
objFS.Close();
objResponse.Close();
}
but this code is not giving me the correct response as i want to save file from ftp and this code is writing the data from file in bytes to my file.
my file is a zip file not a text file.
please help me what should i have to do or i am mistunderstanding.

My guess is that it's something to do with the fact that you're using StreamReader. It's possible that on construction it's reading from the stream to try to determine the encoding. As you're not really using it - just the BaseStream - it's pointless and leads to unclear code.
Just use:
Stream inputStream = objResponse.GetResponseStream();
Additionally, you should use using statements for all the streams, and the response.
Oh, and if you're using .NET 4 or higher, use Stream.CopyTo to save yourself some time.

If you're not opposed to using free 3rd party libraries, you can use http://www.enterprisedt.com/products/edtftpnet/download.html
It makes accessing the FTP a lot simpler IMO. Sample code (taken and slightly modified from their documentation):
using (FTPConnection ftp = new FTPConnection())
{
ftpConnection.ServerAddress = "myserver";
ftpConnection.UserName = userName;
ftpConnection.Password = password;
ftpConnection.Connect();
ftpConnection.DownloadFile(localFilePath, remoteFileName);
}

Related

WebClient/ HTTPWeb Some files are not downloaded completely

Good day everyone,
We are currently developing an update service that will automatically update our programs. For this, the latest versions of these programs are provided via a link, which can be downloaded after a login. The service is supposed to download these files now... this works partly also, but somehow certain files (always the same ones) are downloaded with only one kilobyte. Here it doesn't matter if it's a .zip or an .exe file, as it downloads one file of each correctly. Also, it does not seem to matter the size, as sometimes larger files are downloaded, but smaller ones are not. If the provided link is called manually, the files that could not be downloaded automatically can be downloaded normally.
For the automatic download, we have already tried it with the WebClient:
client.Credentials = new NetworkCredential(username, password);
client.DownloadFile(datei.LinkUpdatedatei, _dateiverzeichnis + '/' + Path.GetFileName(datei.LinkUpdatedatei));
Also, we have already tried it with an HTTPWebRequest:
foreach (UpdateDatei datei in BezieheUpdatedateipfade())
{
using (FileStream fileStream = new System.IO.FileStream(_dateiverzeichnis + '/' + Path.GetFileName(datei.LinkUpdatedatei), System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write))
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(datei.LinkUpdatedatei);
request.Method = WebRequestMethods.Http.Get;
request.PreAuthenticate = true;
//ToDo: Credentials aus config auslesen
request.Credentials = new NetworkCredential(username, password);
const int BUFFER_SIZE = 16 * 1024;
{
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
var buffer = new byte[BUFFER_SIZE];
int bytesRead;
do
{
bytesRead = responseStream.Read(buffer, 0, BUFFER_SIZE);
fileStream.Write(buffer, 0, bytesRead);
} while (bytesRead > 0);
}
}
fileStream.Close();
}
}
}
The result is always the same and the same files are not downloaded correctly:
Please don't take offense if I forgot or overlooked anything... this is one of my first entries - thanks!

How to upload a file from a MemoryStream to an FTP server

I created a simple application that collects form data, generates an XML in memory as a MemoryStream object, and and delivers the XML to a server using SMB. The delivery method is simple for SMB:
var outputFile = new FileStream($#"{serverPath}\{filename}.xml", FileMode.Create);
int Length = 256;
Byte[] buffer = new Byte[Length];
int bytesRead = stream.Read(buffer, 0, Length);
while (bytesRead > 0)
{
outputFile.Write(buffer, 0, bytesRead);
bytesRead = stream.Read(buffer, 0, Length);
}
However, I need to create an alternative delivery method using FTP (with credentials). I don't want to rewrite my XML method, as creating it in memory saves writing to disk which has been a problem in our environment in the past.
I have not been able to find any examples that explain (for a person of very limited coding ability) how such a thing may be accomplished.
Generally when I have need to upload a file to an FTP server, I use something like this:
using (var client = new WebClient())
{
client.Credentials = new NetworkCredential("user", "pass");
client.UploadFile(uri, WebRequestMethods.Ftp.UploadFile, filename.xml);
}
Can this be adapted to upload from a MemoryStream instead of a file on disk?
If not, what other way could I upload a MemoryStream to an FTP server?
Either use FtpWebRequest, as you can see in Upload a streamable in-memory document (.docx) to FTP with C#?:
WebRequest request =
WebRequest.Create("ftp://ftp.example.com/remote/path/filename.xml");
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(username, password);
using (Stream ftpStream = request.GetRequestStream())
{
memoryStream.CopyTo(ftpStream);
}
or use WebClient.OpenWrite (as you can also see in the answer by #Neptune):
using (var webClient = new WebClient())
{
const string url = "ftp://ftp.example.com/remote/path/filename.xml";
using (Stream uploadStream = client.OpenWrite(url))
{
memoryStream.CopyTo(uploadStream);
}
}
Equivalently, your existing FileStream code can be simplified to:
using (var outputFile = File.Create($#"{serverPath}\{filename}.xml"))
{
stream.CopyTo(outputFile);
}
Though obviously, even better would be to avoid the intermediate MemoryStream and write the XML directly to FileStream and WebRequest.GetRequestStream (using their common Stream interface).
You can use the methods OpenWrite/OpenWriteAsync to get a stream that you can write to from any source (stream/array/...etc.)
Here is an example using OpenWrite to write from a MemoryStream:
var sourceStream = new MemoryStream();
// Populate your stream with data ...
using (var webClient = new WebClient())
{
using (Stream uploadStream = client.OpenWrite(uploadUrl))
{
sourceStream.CopyTo(uploadStream);
}
}

Write to web text file

I am programming in Microsoft Visual C# 2010 Express.
I have a text file in a folder on my web server containing one character: '0'.
When I start my C# Application I want to read the number from my text file, increase it by 1, and then save the new number instead.
I've browsed the web but I can't find a good answer. All I get is questions and answers about writing/reading from local text files.
So basically, I want to write some text to a text file which is not on my computer but here:
http://mywebsite.xxx/something/something/myfile.txt
Is this possible?
You may have to adjust the path directory, but this works:
string path = Path.GetDirectoryName(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile) + "\\something\\myfile.txt";
string previousNumber = System.IO.File.ReadAllText(path);
int newNumber;
if (int.TryParse(previousNumber, out newNumber))
{
newNumber++;
using (FileStream fs = File.Create(path, 1024))
{
Byte[] info = new UTF8Encoding(true).GetBytes(newNumber.ToString());
fs.Write(info, 0, info.Length);
}
}
I found a working solution, using File Transport Protocol as Barta Tamás mentioned.
However, I learned from Michael Todd that this is not safe, so I will not use it in my own application, but maybe it can be helpful to someone else.
I found information about uploading files using FTP here: http://msdn.microsoft.com/en-us/library/ms229715.aspx
void CheckNumberOfUses()
{
// Get the objects used to communicate with the server.
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create("ftp://mywebsite.xx/public_html/something1/something2/myfile.txt");
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create("http://mywebsite.xx/something1/something2/myfile.txt");
StringBuilder sb = new StringBuilder();
byte[] buf = new byte[8192];
HttpWebResponse response = (HttpWebResponse)httpRequest.GetResponse();
Stream resStream = response.GetResponseStream();
string tempString = null;
int count = resStream.Read(buf, 0, buf.Length);
if (count != 0)
{
tempString = Encoding.ASCII.GetString(buf, 0, count);
int numberOfUses = int.Parse(tempString) + 1;
sb.Append(numberOfUses);
}
ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
// This example assumes the FTP site uses anonymous logon.
ftpRequest.Credentials = new NetworkCredential("login", "password");
// Copy the contents of the file to the request stream.
byte[] fileContents = Encoding.UTF8.GetBytes(sb.ToString());
ftpRequest.ContentLength = fileContents.Length;
Stream requestStream = ftpRequest.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
FtpWebResponse ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpResponse.Close();
}
Read in the comments of the question how this can be done better, not using FTP. My solution is not suggested if you have important files on your server.

FtpWebRequest Download File Incorrect Size

I’m using the following code to download a file from a remote ftp server:
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverPath);
request.KeepAlive = true;
request.UsePassive = true;
request.UseBinary = true;
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential(userName, password);
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
using (Stream responseStream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(responseStream))
using (StreamWriter destination = new StreamWriter(destinationFile))
{
destination.Write(reader.ReadToEnd());
destination.Flush();
}
The file that I’m downloading is a dll and my problem is that it is being altered by this process in some way. I know this because the file size is increasing. I have a suspicion that this section of code is at fault:
destination.Write(reader.ReadToEnd());
destination.Flush();
Can anyone offer any ideas as to what may be wrong?
StreamReader and StreamWriter work with character data, so you are decoding the stream from bytes to characters and then encoding it back to bytes again. A dll file contains binary data, so this round-trip conversion will introduce errors. You want to read bytes directly from the responseStream object and write to a FileStream that isn't wrapped in a StreamWriter.
If you are using .NET 4.0 you can use Stream.CopyTo, but otherwise you will have to copy the stream manually. This StackOverflow question has a good method for copying streams:
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
while (true)
{
int read = input.Read(buffer, 0, buffer.Length);
if (read <= 0)
return;
output.Write(buffer, 0, read);
}
}
So, your code will look like this:
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
using (Stream responseStream = response.GetResponseStream())
using (FileStream destination = File.Create(destinationFile))
{
CopyStream(responseStream, destination);
}

FTP in C# returning corrupted file, why?

I have this method to transfer files using a FTP Server:
private void TransferNeededFiles(IEnumerable<string> filenames)
{
foreach (var filename in filenames)
{
var request = WebRequest.Create(new Uri(#"ftp://{0}/{1}".Fill(Config.ServerUri, filename))) as FtpWebRequest;
if (request != null)
{
request.Credentials = new NetworkCredential(Config.Username, Config.Password);
request.Method = WebRequestMethods.Ftp.DownloadFile;
using (var streamReader = new StreamReader(request.GetResponse().GetResponseStream()))
{
var fileStream = new FileStream(#"{0}/{1}".Fill(Config.DestinationFolderPath, filename), FileMode.Create);
var writer = new StreamWriter(fileStream);
writer.Write(streamReader.ReadToEnd());
writer.Flush();
writer.Close();
fileStream.Close();
}
}
}
}
A .gz file, included in the list of filenames, is always corrupted. When I try to copy from ftp using windows explorer, the file is not corrupted. Do you know what is happening?
The problem is this line:
writer.Write(streamReader.ReadToEnd());
StreamReader.ReadToEnd() returns a Unicode encoded string. You want something that will read the stream byte for byte.
Readers and Writers work with Unicode characters. To transfer binary data you want to be working with raw bytes, so you should be using plain Streams. You can copy from one stream to another with a loop like the following:
BufferedStream inputStream, outputStream;
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.Read(buffer)) > 0)
{
outputStream.Write(buffer, 0, bytesRead);
}
A good thing about this is that it will also only use a fixed amount of memory rather than reading the entire file into memory at once.

Categories