I have been working on a simple program to connect to FTP server and download a ZIP file. It makes the connection, authenticates and downloads the zip folder, but the contents are empty. I cant figure it out, please help! Thanks!
Console.WriteLine("downloading file . . . " + ary_connect[3]);
FtpWebRequest requestFileDownload = (FtpWebRequest)WebRequest.Create(ary_connect[0]);
requestFileDownload.Credentials = new NetworkCredential(ary_connect[1], ary_connect[2]);
requestFileDownload.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponse responseFileDownload = (FtpWebResponse)requestFileDownload.GetResponse();
byte[] buffer = new byte[32768];
using (Stream input = responseFileDownload.GetResponseStream())
{
using (FileStream output = new FileStream(ary_connect[4] + ary_connect[3], FileMode.Create))
{
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
}
}
Related
I have tried to download an FTP file using C# and have had various problems. What I want to achieve is to be able to show download progress in a progressBar. It is important that I use Windows Form and .Net.
I have tried two codes;
My first code works perfectly, that is, I can download the FTP file without problems.
CODE 1
FtpWebRequest dirFtp = ((FtpWebRequest)FtpWebRequest.Create(ficFTP));
dirFtp.KeepAlive = true;
dirFtp.UsePassive = UsePassive;
dirFtp.UseBinary = UseBinary;
// Los datos del usuario (credenciales)
NetworkCredential cr = new NetworkCredential(user, pass);
dirFtp.Credentials = cr;
FtpWebResponse response = (FtpWebResponse)dirFtp.GetResponse();
long size = (long)response.ContentLength;
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
using (FileStream writer = new FileStream(dirLocal, FileMode.Create))
{
int bufferSize = 2048;
int readCount;
byte[] buffer = new byte[2048];
readCount = responseStream.Read(buffer, 0, bufferSize);
while (readCount > 0)
{
writer.Write(buffer, 0, readCount);
readCount = responseStream.Read(buffer, 0, bufferSize);
}
}
lblDescarga.Text = "¡Downloaded!";
reader.Close();
response.Close();
Problem with this code
My problem with this code is that I can't get the size of the FTP file to be able to use the progressBar, In theory this section of code would tell me the size of my file but it always returns -1:
long size = (long)response.ContentLength;
As this did not work as I wanted, I made a post and people recommended this solution FtpWebRequest FTP download with ProgressBar:
CODE 2
try
{
const string url = "ftp://185.222.111.11:21/patch/archive.zip";
NetworkCredential credentials = new NetworkCredential("user", "pass");
// Query size of the file to be downloaded
WebRequest sizeRequest = WebRequest.Create(url);
sizeRequest.Credentials = credentials;
sizeRequest.Method = WebRequestMethods.Ftp.GetFileSize;
int size = (int)sizeRequest.GetResponse().ContentLength;
progressBar1.Invoke(
(MethodInvoker)(() => progressBar1.Maximum = size));
// Download the file
WebRequest request = WebRequest.Create(url);
request.Credentials = credentials;
request.Method = WebRequestMethods.Ftp.DownloadFile;
using (Stream ftpStream = request.GetResponse().GetResponseStream())
using (Stream fileStream = File.Create(#"C:\tmp\archive.zip"))
{
byte[] buffer = new byte[10240];
int read;
while ((read = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
{
fileStream.Write(buffer, 0, read);
int position = (int)fileStream.Position;
progressBar1.Invoke(
(MethodInvoker)(() => progressBar1.Value = position));
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
Problem with this code
The problem with this code is when it gets to this point:
int size = (int) sizeRequest.GetResponse (). ContentLength;
Remote server error: (550) File not available (eg file not found or not accessed).
The truth is that it is impossible to tell that you do not have permission if code 1 works well. However I have the normal permissions in FTP, could someone give me an idea please?
I'm using .NET 3.5 and I need to transfer by FTP some files.
I don't want to use files because I manage all by using MemoryStream and bytes arrays.
Reading these articles (article and article), I made my client.
public void Upload(byte[] fileBytes, string remoteFile)
{
try
{
string uri = string.Format("{0}:{1}/{2}", Hostname, Port, remoteFile);
FtpWebRequest ftp = (FtpWebRequest)WebRequest.Create(uri);
ftp.Credentials = new NetworkCredential(Username.Normalize(), Password.Normalize());
ftp.UseBinary = true;
ftp.UsePassive = true;
ftp.Method = WebRequestMethods.Ftp.UploadFile;
using (Stream localFileStream = new MemoryStream(fileBytes))
{
using (Stream ftpStream = ftp.GetRequestStream())
{
int bufferSize = (int)Math.Min(localFileStream.Length, 2048);
byte[] buffer = new byte[bufferSize];
int bytesSent = -1;
while (bytesSent != 0)
{
bytesSent = localFileStream.Read(buffer, 0, bufferSize);
ftpStream.Write(buffer, 0, bufferSize);
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLog(logs, "Errore Upload", ex);
throw;
}
}
The FTP client connects, writes and close correctly without any error. But the written files are corrupted, such as PDF cannot be opened and for DOC/DOCX Word shows a message about file corruption and tries to restore them.
If I write to a file the same bytes passed to the Upload method, I get a correct file. So the problem must be with FTP transfer.
byte[] fileBytes = memoryStream.ToArray();
File.WriteAllBytes(#"C:\test.pdf", fileBytes); // --> File OK!
ftpClient.Upload(fileBytes, remoteFile); // --> File CORRUPTED on FTP folder!
You need to use bytesSent in the Write call:
bytesSent = localFileStream.Read(buffer, 0, bufferSize);
ftpStream.Write(buffer, 0, bytesSent);
Otherwise you write too many bytes in the last round.
I have got a code to download a file using ftprequest
FtpWebRequest requestFileDownload = (FtpWebRequest)WebRequest.Create("ftp://localhost/Source/" + fileName);
requestFileDownload.Credentials = new NetworkCredential("khanrahim", "arkhan22");
requestFileDownload.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponse responseFileDownload = (FtpWebResponse)requestFileDownload.GetResponse();
Stream responseStream = responseFileDownload.GetResponseStream();
FileStream writeStream = new FileStream(localPath + fileName, FileMode.Create);
int Length = 2048;
Byte[] buffer = new Byte[Length];
int bytesRead = responseStream.Read(buffer, 0, Length);
while (bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = responseStream.Read(buffer, 0, Length);
}
responseStream.Close();
writeStream.Close();
Now my need is that i need to delete the file from ftpserver once download is complete using the same requset.
I did try appending
requestFileDownload.Method = WebRequestMethods.Ftp.deleteFile;
before closing the request ..But it is not working.
How can i delete the file using the same request.
Objects created by WebRequest.Create can be used for exactly one request. Since there is no "GET and DELETE" method in FTP you need to create another FtpWebRequest with the same configuration and send delete request with that new FtpWebRequest.
I think I have some memory issue with a function that should download a file from ftp server. The reason that I think it's a memory thing is because it works fine during debug (maybe it gives the garbage collector more time). Yet I thought that the using should solve this...
Just to be clear the function works when called once yet calling it several times in a for loop invokes the err message: 550 The specified network name is no longer available.
Please help
Asaf
private void downloadFile(string sourceFile, string targetFolder)
{
string remoteFile = sourceFile.Replace("\\","//");
string localFolder = targetFolder + "\\" + sourceFile.Substring(sourceFile.LastIndexOf("\\")+1);
string filename = "ftp://" + ftpServerIP + "//" + remoteFile;
FtpWebRequest ftpReq = (FtpWebRequest)WebRequest.Create(filename);
ftpReq.Method = WebRequestMethods.Ftp.DownloadFile;
ftpReq.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
ftpReq.UseBinary = true;
ftpReq.Proxy = null;
ftpReq.KeepAlive = false; //'3. Settings and action
try
{
using (System.Net.FtpWebResponse response = (System.Net.FtpWebResponse)(ftpReq.GetResponse()))
{
using (System.IO.Stream responseStream = response.GetResponseStream())
{
using (System.IO.FileStream fs = new System.IO.FileStream(localFolder, System.IO.FileMode.Create))
{
Byte[] buffer = new byte[2047];
int read = 0;
do
{
read = responseStream.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, read);
} while (read == 0);
responseStream.Close();
fs.Flush();
fs.Close();
}
responseStream.Close();
}
response.Close();
}
}
catch (WebException ex)
{
FtpWebResponse response = (FtpWebResponse)ex.Response;
Console.Out.WriteLine(response.StatusDescription);
}
}
There's a bug in the read loop that causes large files to be truncated. Use:
int read;
while ((read = responseStream.Read(buffer, 0, buffer.Length)) != 0)
{
fs.Write(buffer, 0, read);
}
With that change in place I was able to download a number of large files via FTP without encountering exceptions.
I'm using the following C# code to FTP a ~40MB CSV file from a remote service provider. Around 50% of the time, the download hangs and eventually times out. In my app log, I get a line like:
> Unable to read data from the transport
> connection: A connection attempt
> failed because the connected party did
> not properly respond after a period of
> time, or established connection failed
> because connected host has failed to
> respond.
When I download the file interactively using a graphical client like LeechFTP, the downloads almost never hang, and complete in about 45 seconds. I'm having a hell of a time understanding what's going wrong.
Can anyone suggest how I can instrument this code to get more insight into what's going on, or a better way to download this file? Should I increase the buffer size? By how much? Avoid the buffered writes to disk and try to swallow the whole file in memory? Any advice appreciated!
...
private void CreateDownloadFile()
{
_OutputFile = new FileStream(_SourceFile, FileMode.Create);
}
public string FTPDownloadFile()
{
this.CreateDownloadFile();
myReq = (FtpWebRequest)FtpWebRequest.Create(new Uri(this.DownloadURI));
myReq.Method = WebRequestMethods.Ftp.DownloadFile;
myReq.UseBinary = true;
myReq.Credentials = new NetworkCredential(_ID, _Password);
FtpWebResponse myResp = (FtpWebResponse)myReq.GetResponse();
Stream ftpStream = myResp.GetResponseStream();
int bufferSize = 2048;
int readCount;
byte[] buffer = new byte[bufferSize];
int bytesRead = 0;
readCount = ftpStream.Read(buffer, 0, bufferSize);
while (readCount > 0)
{
_OutputFile.Write( buffer, 0, readCount );
readCount = ftpStream.Read( buffer, 0, bufferSize );
Console.Write( '.' ); // show progress on the console
bytesRead += readCount;
}
Console.WriteLine();
logger.logActivity( " FTP received " + String.Format( "{0:0,0}", bytesRead ) + " bytes" );
ftpStream.Close();
_OutputFile.Close();
myResp.Close();
return this.GetFTPStatus();
}
public string GetFTPStatus()
{
return ((FtpWebResponse)myReq.GetResponse()).StatusDescription;
}
I tried to use FTPClient as suggested above and got the same timeout error, FTPClient uses FtpWebRequest so I must be missing something but I don't see the point.
After some more research I found that -1 is the value for infinity
For my purpose it is okay to use infinity so I went with that, problem solved.
Here is my code:
//gets file from FTP site.
FtpWebRequest reqFTP;
string fileName = #"c:\downloadDir\localFileName.txt";
FileInfo downloadFile = new FileInfo(fileName);
string uri = "ftp://ftp.myftpsite.com/ftpDir/remoteFileName.txt";
FileStream outputStream = new FileStream(fileName, FileMode.Append);
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
reqFTP.UseBinary = true;
reqFTP.KeepAlive = false;
reqFTP.Timeout = -1;
reqFTP.UsePassive = true;
reqFTP.Credentials = new NetworkCredential("userName", "passWord");
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream ftpStream = response.GetResponseStream();
long cl = response.ContentLength;
int bufferSize = 2048;
int readCount;
byte[] buffer = new byte[bufferSize];
readCount = ftpStream.Read(buffer, 0, bufferSize);
Console.WriteLine("Connected: Downloading File");
while (readCount > 0)
{
outputStream.Write(buffer, 0, readCount);
readCount = ftpStream.Read(buffer, 0, bufferSize);
Console.WriteLine(readCount.ToString());
}
ftpStream.Close();
outputStream.Close();
response.Close();
Console.WriteLine("Downloading Complete");
I suggest you don't use FtpWebRequest for FTP access. FtpWebRequest is the most brain-dead FTP API I have every seen.
Currently I use FtpClient http://www.codeplex.com/ftpclient
I also have had good luck with IndySockets http://www.indyproject.org/index.en.aspx
I haven't dealt with FTP on a code level, but FTP supports resuming. Maybe you could have it automatically try to resume the upload when it times out