FtpWebRequest Download File Incorrect Size - c#

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);
}

Related

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);
}
}

Problems uploading a binary serialized file

The idea of my program is to allow the user to save his data in a cloud. The data is stored in binary serialized files.
Serialization Code looks like so:
FileStream Stream = new FileStream(..., FileMode.Create); // create stream
BinaryFormatter Formatter = new BinaryFormatter(); // create formatter
Formatter.Serialize(Stream, ObjectToSerialize); // serialize
Stream.Close();
The Problem is that when I upload the serialized file, with the following code:
FtpWebRequest Request = (FtpWebRequest)WebRequest.Create(new Uri(...));
Request.Method = WebRequestMethods.Ftp.UploadFile;
Request.Credentials = new NetworkCredential(..., ...);
string Path = System.IO.Path.GetDirectoryName(...;
StreamReader SourceStream = new StreamReader(Path);
Request.UseBinary = true;
byte[] FileContents = Encoding.Default.GetBytes(SourceStream.ReadToEnd());
SourceStream.Close();
Request.ContentLength = FileContents.Length;
Stream RequestStream = Request.GetRequestStream();
RequestStream.Write(FileContents, 0, FileContents.Length);
RequestStream.Close();
FtpWebResponse Response = (FtpWebResponse)Request.GetResponse();
Response.Close();
the file encoding changes (I am not sure about that.. if the encoding is the problem but I think so) and I am not able to deserialize the file anymore, exceptions occure. Do you have a idea how to do not damage the file?
Best Regards!
Encoding only applies to text, and you're dealing with a binary file here. You should not attempt to read it as a string. The "encoding changed" because you are using Encoding.Default which depends on the current configuration of your operating system.
Just change the code to:
string Path = System.IO.Path.GetDirectoryName(...);
// StreamReader SourceStream = new StreamReader(Path);
// Request.UseBinary = true;
byte[] FileContents = File.ReadAllBytes(Path);
// SourceStream.Close();
if you want to read an entire binary file in memory.

FtpWebRequest download text file: CR/LF removed

I am using FtpWebRequest to download files, but in all text files all \r\n are removed when downloaded.
What am I doing wrong?
Uri u = new Uri(msg);
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(u);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = credential;
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
//Get a reponse
WebResponse response = request.GetResponse();
Stream responseStream = response.GetResponseStream();
FileStream localfileStream = new FileStream(destination,
FileMode.Create, FileAccess.Write);
//create the file
byte[] buffer = new byte[1024];
int bytesRead = responseStream.Read(buffer, 0, 1024);
while (bytesRead != 0)
{
localfileStream.Write(buffer, 0, bytesRead);
bytesRead = responseStream.Read(buffer, 0, 1024);
}
localfileStream.Close();
response.Close();
responseStream.Close();.
Your code is correct. There is something else you are not telling that causing the problem. My guess would be
a) File on the server does not have \r\n
b) The way how you check that it does not have them on the client is wrong. Either you are checking a wrong file, or it had gone additional transformation or something else.
I've had a similar problem to this. The code I used is almost identical to yours. I found that the code for me was actually working correctly, but the file on the server only contained the the "LF" character at the end of the line, not the "CR/LF" combo. Most text editors ignore this, and display the text as one continuous line.

How to download ZipFile From FTP server

I have zip file in ftp server,this zip file contain more then one xml file in it,i want to download this zipfile and save to local disk,i have write below code,i download file but when i try to Extract this zip it throw me error that File is corrupted......
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(_remoteHost + file);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential(_remoteUser, _remotePass);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
StreamWriter writer = new StreamWriter(destination);
writer.Write(reader.ReadToEnd());
writer.Close();
reader.Close();
response.Close();
You are channeling the result of the FTP request through a StreamReader. This has the usually beneficial effect of handling character encoding, but is not something you ever want to do when dealing with binary data (i.e. a zip file). Instead, you should read the data directly from the stream. Something like:
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(_remoteHost + file);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential(_remoteUser, _remotePass);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
// Copy the data from the responseStream to destination 1k at a time (feel free to increase buffer size)
byte[] buffer = new byte[1024];
for (int amountRead = responseStream.Read(buffer, 0, buffer.Length); amountRead > 0; amountRead = responseStream.Read(buffer, 0, buffer.Length))
{
destination.Write(buffer, 0, amountRead);
}
destination.Flush();
response.Close();
Here are sample code for Download file from FTP Server
Uri url = new Uri("ftp://ftp.demo.com/file1.txt");
if (url.Scheme == Uri.UriSchemeFtp)
{
FtpWebRequest objRequest = (FtpWebRequest)FtpWebRequest.Create(url);
//Set credentials if required else comment this Credential code
NetworkCredential objCredential = new NetworkCredential("FTPUserName", "FTPPassword");
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(Server.MapPath("file1.txt"), 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();
}
I think that your problem is the way that you download the zip, here's an article explaining how to use it, i hope it helps:
http://www.vcskicks.com/download-file-ftp.php
Also, there is a question like this here:
how to download compressed file (.zip) through FTP using c#?

using http response how to save the pdf files

I've written following code to get the content from a web page and save to the system.
if the webpage is in html format i'm able to save it.
if the web page is in pdf format i'm unable to save it. After saving if i opend the file blank pages are coming.
I want to know How to save the pdf files from the response.
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(Url);
WebResponse response = request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
webContent = reader.ReadToEnd();
StreamWriter sw = new StreamWriter(FileName);
sw.WriteLine(webContent);
sw.Close();
Please help me ASAP.
StreamReader.ReadToEnd() returns a string. PDF files are binary, and contain data that is not string-friendly. You need to read it into a byte array, and write the byte array to disk. Even better, use a smaller byte array as a buffer and read in small chunks.
You can also simplify the whole thing by just using webclient:
using (var wc = new System.Net.WebClient())
{
wc.DownloadFile(Url, FileName);
}
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(Url);
WebResponse response = request.GetResponse();
using (Stream stream = response.GetResponseStream())
using (FileStream fs = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
stream.BlockCopy(fs);
}
...
public static class StreamHelper
{
public static void Copy(Stream source, Stream target, int blockSize)
{
int read;
byte[] buffer = new byte[blockSize];
while ((read = source.Read(buffer, 0, blockSize)) > 0)
{
target.Write(buffer, 0, read);
}
}
public static void BlockCopy(this Stream source, Stream target, int blockSize = 65536)
{
Copy(source, target, blockSize);
}
}

Categories