I'm trying to download a directory, using FTP in a C# application. I basically need to take a remote dir, and move it, and its contents into a local dir.
Here is the function I'm currently using, and what the log output and errors are. The sample I'm referencing is for getting files, and possibly not directories:
private void Download(string file, string destination)
{
try
{
string getDir = "ftp://" + ftpServerIP + ftpPath + file + "/";
string putDir = destination + "\\" + file;
Debug.WriteLine("GET: " + getDir);
Debug.WriteLine("PUT: " + putDir);
FtpWebRequest reqFTP;
reqFTP = (FtpWebRequest)FtpWebRequest.Create
(new Uri(getDir));
reqFTP.Credentials = new NetworkCredential(ftpUserID,
ftpPassword);
reqFTP.UseBinary = true;
reqFTP.KeepAlive = false;
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
reqFTP.Proxy = null;
reqFTP.UsePassive = false;
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream responseStream = response.GetResponseStream();
FileStream writeStream = new FileStream(putDir, 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);
}
writeStream.Close();
response.Close();
}
catch (WebException wEx)
{
MessageBox.Show(wEx.Message, "Download Error");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Download Error");
}
}
Debug:
GET: ftp://I.P.ADDR/SOME_DIR.com/members/forms/THE_FOLDER_TO_GET/
PUT: C:\Users\Public\Documents\iMacros\Macros\THE_FOLDER_TO_WRITE
A first chance exception of type 'System.Net.WebException' occurred in System.dll
MessageBox Output:
The requested URI is invalid for this FTP command.
The slash on the end of the getDir indicates a directory - can you use mget and pass a path like that ends in "/*"?
Related
In my code I want to upload and download a specific JSON-File to a FTP-Server.
The serializing works great and also the upload. When i look up the file via - for example - FileZilla, the content of the file is correct. (on the server)
But when i download this file with my application (and with my code - NOT with FileZilla), I don't get any exceptions, but the file is nearly empty. This is the only content:
{}
And here is my code for downloading:
string ResponseDescription = "";
FtpWebRequest req = (FtpWebRequest)FtpWebRequest.Create("ftp://" + "ftp.strato.com" + "/" + verzeichnis + "/" + file.Name);
req.Method = WebRequestMethods.Ftp.DownloadFile;
req.Credentials = new NetworkCredential(this.benutzer, this.passwort);
req.UseBinary = true;
req.UsePassive = false;
req.Proxy = null;
try
{
FtpWebResponse response = (FtpWebResponse)req.GetResponse();
Stream stream = response.GetResponseStream();
byte[] buffer = new byte[2048];
FileStream fs = new FileStream(destinationFolder + #"/" + destinationFile.Name, FileMode.Create);
int ReadCount = stream.Read(buffer, 0, buffer.Length);
while (ReadCount > 0)
{
fs.Write(buffer, 0, ReadCount);
ReadCount = stream.Read(buffer, 0, buffer.Length);
}
ResponseDescription = response.StatusDescription;
fs.Close();
stream.Close();
return true;
}
catch (Exception e)
{
MessageBox.Show(e.Message); // TODO - better Errorhandling
return false;
}
I found the solution. It was my mistake. The problem wasnt the download - the code was correct (as you said).
After downloading the file the JSON-Deserialization runs and here was the cause. I had a little mistake in my deserialization-logic.
I wrote a simple C# program to transfer ACCDE files from a FTP server to a client's desktop. The transferring seems to work fine, however, when I open the file and try to use the program, it gives me the message "Requested type library or wizard is not a VBA project."
When I transfer the ACCDB source code, it seems to work fine. This is the transfer function:
private void DownloadFileFTP(string fileName, string localFilePath, bool isXmlSchema)
{
string ftpFilePath = redacted;
if (isXmlSchema)
{
ftpFilePath = ftpFilePath + fileName;
label3.Text = "Fetching update information...";
}
else
{
ftpFilePath = ftpFilePath + Properties.Settings.Default.Customer + "/" + fileName;
label3.Text = "Updating " + fileName;
}
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpFilePath);
request.Credentials = new NetworkCredential(redacted, redacted);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.EnableSsl = Properties.Settings.Default.SSL;
request.UsePassive = Properties.Settings.Default.Passive;
int bytesRead = 0;
byte[] buffer = new byte[2048];
Stream reader = request.GetResponse().GetResponseStream();
FileStream fs = new FileStream(localFilePath, FileMode.Create);
while(true)
{
bytesRead = reader.Read(buffer, 0, buffer.Length);
if (bytesRead == 0)
break;
fs.Write(buffer, 0, bytesRead);
}
fs.Close();
}
My questions, I suppose, are: am I doing something wrong here? Do ACCDE files not play nice with FileStreams or something? I am still quite new to .NET so any help would be very appreciated.
EDIT: It seems one of the references was causing the problem.
You didn't close stream and ftpWebRequest.
Try this, made with you script, just copy/paste (fix some error if it have :) ):
private void DownloadFileFTP(string fileName, string localFilePath, bool isXmlSchema)
{
FileStream fs = null;
try
{
fileName = Regex.Replace(fileName.ToString(), #"\s.*$", "").Trim();
string ftpFilePath = redacted;
if (isXmlSchema)
{
ftpFilePath = ftpFilePath + fileName;
label3.Text = "Fetching update information...";
}
else
{
ftpFilePath = ftpFilePath + Properties.Settings.Default.Customer + "/" + fileName;
label3.Text = "Updating " + fileName;
}
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpFilePath);
request.Credentials = new NetworkCredential(redacted, redacted);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.EnableSsl = Properties.Settings.Default.SSL;
request.UsePassive = Properties.Settings.Default.Passive;
int bytesRead = 0;
int bufferSize = 2048;
byte[] buffer = new byte[bufferSize];
Stream reader = request.GetResponseStream();
bytesRead = reader.Read(buffer, 0, bufferSize);
fs = new FileStream(localFilePath, FileMode.Create);
while (bytesRead > 0)
{
fs.Write(buffer, 0, bytesRead);
bytesRead = reader.Read(buffer, 0, bufferSize);
}
reader.Close();
request.Close();
}
catch (Exception ex)
{
label3.Text = "Error: " + ex.ToString;
}
finally
{
if (fs != null)
{
fs.Close();
}
}
}
First time poster, long-time reader. I have a really annoying problem thats been getting on my nerves. Ive got a program set up so I listen for new files on an FTP server, if theres a new file I download it. From there I work on some of the information in the file, etc. My problem comes when I run through my sequence the second time. That is, on the first file I download everything is totally fine, but as soon as a new file gets detected and my program tries downloading it, my program just hangs.
private static void DownloadFile(string s)
{
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://blabla.com/"+s);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential("xxx" ,"zzz");
using (FtpWebResponse partResponse = (FtpWebResponse)request.GetResponse())
{
Stream partReader = partResponse.GetResponseStream();
byte[] buffer = new byte[1024];
FileInfo fi = new FileInfo(path);
FileStream memStream = fi.Create();
while (true)
{
int bytesRead = partReader.Read(buffer, 0, buffer.Length - 1);
if (bytesRead == 0)
break;
memStream.Write(buffer, 0, bytesRead);
}
partResponse.Close();
memStream.Close();
}
Console.WriteLine(DateTime.Now + " file downloaded");
MoveFileToInProgress(s);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
The line it hangs on is this one:
using (FtpWebResponse partResponse = (FtpWebResponse)request.GetResponse())
The reason my method here is static is because Im just running it in a different project to test it.. My question here is, how come it only ever dies on the second file? Ive been staring myself blind for hours now!
I ran into this problem as well... try finishing your request first and then closing it before trying to retrieve the response. That worked for me (actually tried it after reading comment by MartinNielsen). Here is what I did.
// connect to the ftp site
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(ftpUri);
ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
ftpRequest.Credentials = new NetworkCredential(ftpUser, ftpPassword);
// setting proxy to null so that it does not go through the proxy
ftpRequest.Proxy = null;
// get file information
StreamReader fileStream = new StreamReader(filePath);
byte[] fileBytes = Encoding.UTF8.GetBytes(fileStream.ReadToEnd());
ftpRequest.ContentLength = fileBytes.Length;
fileStream.Close();
// open connection to ftp site
Stream ftpRequestStream = ftpRequest.GetRequestStream();
// write the file to the stream
ftpRequestStream.Write(fileBytes, 0, fileBytes.Length);
// close the stream
ftpRequestStream.Close();
// get the response from the server
FtpWebResponse ftpUploadResponse = (FtpWebResponse)ftpRequest.GetResponse();
string result = ftpUploadResponse.StatusDescription;
// close response
ftpUploadResponse.Close();
// return response to calling code
return result;
Here are a couple of the resources that I used when writing this code (won't let me post more than 2, there were more)
How to: Upload Files with FTP
Uploading a file -- "The requested URI is invalid for this FTP command"
I'm not expert on C# but I use this code to download files from my ftp:
public void Download(string filename)
{
// I try to download five times before crash
for (int i = 1; i < 5; i++)
{
try
{
FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(Global.Path + "/" + filename);
ftp.Credentials = new NetworkCredential(User, Pass);
ftp.KeepAlive = false;
ftp.Method = WebRequestMethods.Ftp.DownloadFile;
ftp.UseBinary = true;
ftp.Proxy = null;
int buffLength = 2048;
byte[] buff = new byte[buffLength];
int contentLen;
string LocalDirectory = Application.StartupPath.ToString() + "/downloads/" + filename;
using (FileStream fs = new FileStream(LocalDirectory, FileMode.Create, FileAccess.Write, FileShare.None))
using (Stream strm = ftp.GetResponse().GetResponseStream())
{
contentLen = strm.Read(buff, 0, buffLength);
while (contentLen != 0)
{
fs.Write(buff, 0, contentLen);
contentLen = strm.Read(buff, 0, buffLength);
}
}
Process.Start(LocalDirectory);
break;
}
catch (Exception exc)
{
if (i == 5)
{
MessageBox.Show("Can't download, try number: " + i + "/5 \n\n Error: " + exc.Message,
"Problem downloading the file");
}
}
}
}
Tell me if it works for you :)
I get "System.NotSupportedException: The given path's format is not supported. at System.Security.Util.StringExpressionSet" when trying to download an item from an ftp(which have access to). The upload seems to work fine and is done similarly I'll post both functions below:
private void Download(string filePath, string fileName)
{
FtpWebRequest reqFTP;
try
{
//filePath = <<The full path where the file is to be created. the>>,
//fileName = <<Name of the file to be createdNeed not name on FTP server. name name()>>
Label1.Text = filePath + "/" + fileName;
FileStream outputStream = new FileStream(filePath + "/" + fileName, FileMode.Create);
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new
Uri("ftp://" + ftpServerIP + "/" + fileName));
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
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);
while (readCount > 0)
{
outputStream.Write(buffer, 0, readCount);
readCount = ftpStream.Read(buffer, 0, bufferSize);
}
ftpStream.Close();
outputStream.Close();
response.Close();
}
catch (Exception ex)
{
Label1.Text = ex.ToString();
}
}
public void Upload(string filename)
{
FileInfo fileInf = new FileInfo(filename);
string uri = "ftp://" + ftpServerIP + "/" + fileInf.Name;
FtpWebRequest reqFTP;
// Create FtpWebRequest object from the Uri provided
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpServerIP +"/" + fileInf.Name));
// Provide the WebPermission Credintials
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
// By default KeepAlive is true, where the control connection is not closed
// after a command is executed.
reqFTP.KeepAlive = false;
// Specify the command to be executed.
reqFTP.Method = WebRequestMethods.Ftp.UploadFile;
// Specify the data transfer type.
reqFTP.UseBinary = true;
// Notify the server about the size of the uploaded file
reqFTP.ContentLength = fileInf.Length;
// The buffer size is set to 2kb
int buffLength = 2048;
byte[] buff = new byte[buffLength];
int contentLen;
// Opens a file stream (System.IO.FileStream) to read the file to be uploaded
FileStream fs = fileInf.OpenRead();
try
{
// Stream to which the file to be upload is written
Stream strm = reqFTP.GetRequestStream();
// Read from the file stream 2kb at a time
contentLen = fs.Read(buff, 0, buffLength);
// Till Stream content ends
while (contentLen != 0)
{
// Write Content from the file stream to the FTP Upload Stream
strm.Write(buff, 0, contentLen);
contentLen = fs.Read(buff, 0, buffLength);
}
// Close the file stream and the Request Stream
strm.Close();
fs.Close();
}
catch (Exception ex)
{
//MessageBox.Show(ex.Message, "Upload Error");
}
}
and these are the function calls
protected void btnDownload_Click(object sender, EventArgs e)
{
string FullServer = "ftp://" + ftpServerIP;
Download(FullServer, LbxServer.SelectedValue);
}
protected void btnUpload_Click(object sender, EventArgs e)
{
Upload(LbxLocal.SelectedValue);
}
Thank you all for any help on this matter.
I think you'll find that ftp://myservername is an invalid scheme for a new FileStream. Note that your FileStream represents the local target, not the remote file.
If your intent is to download a remote file to your local system, filePath should refer to a folder on your local network (e.g., C:\temp or \\somecomputer\share, etc.)
The following code is good for uploading text files, but it fails to upload JPEG files (not completely - the file name is good but the image is corrupted):
private void up(string sourceFile, string targetFile)
{
try
{
string ftpServerIP = ConfigurationManager.AppSettings["ftpIP"];
string ftpUserID = ConfigurationManager.AppSettings["ftpUser"];
string ftpPassword = ConfigurationManager.AppSettings["ftpPass"];
//string ftpURI = "";
string filename = "ftp://" + ftpServerIP + "//" + targetFile;
FtpWebRequest ftpReq = (FtpWebRequest)WebRequest.Create(filename);
ftpReq.Method = WebRequestMethods.Ftp.UploadFile;
ftpReq.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
StreamReader stream = new StreamReader(sourceFile);
Byte[] b = System.Text.Encoding.UTF8.GetBytes(stream.ReadToEnd());
stream.Close();
ftpReq.ContentLength = b.Length;
Stream s = ftpReq.GetRequestStream();
s.Write(b, 0, b.Length);
s.Close();
System.Net.FtpWebResponse ftpResp = (FtpWebResponse)ftpReq.GetResponse();
MessageBox.Show(ftpResp.StatusDescription);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
I have another solution that can upload a file:
private void Upload(string sourceFile, string targetFile)
{
string ftpUserID;
string ftpPassword;
string ftpServerIP;
ftpServerIP = ConfigurationManager.AppSettings["ftpIP"];
ftpUserID = ConfigurationManager.AppSettings["ftpUser"];
ftpPassword = ConfigurationManager.AppSettings["ftpPass"];
FileInfo fileInf = new FileInfo(sourceFile);
FtpWebRequest reqFTP;
// Create FtpWebRequest object from the Uri provided
reqFTP = (FtpWebRequest)(FtpWebRequest.Create(new Uri("ftp://" + ftpServerIP + "//" + targetFile)));
// Provide the WebPermission Credintials
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
// Bypass default lan settings
reqFTP.Proxy = null;
// By default KeepAlive is true, where the control connection is not closed
// after a command is executed.
reqFTP.KeepAlive = false;
// Specify the command to be executed.
reqFTP.Method = WebRequestMethods.Ftp.UploadFile;
// Specify the data transfer type.
reqFTP.UseBinary = true;
// Notify the server about the size of the uploaded file
reqFTP.ContentLength = fileInf.Length;
// The buffer size is set to 2kb
int buffLength = 2048;
Byte[] buff;
buff = new byte[buffLength];
int contentLen;
// Opens a file stream (System.IO.FileStream) to read the file to be uploaded
FileStream fs = fileInf.OpenRead();
try
{
// Stream to which the file to be upload is written
Stream strm = reqFTP.GetRequestStream();
// Read from the file stream 2kb at a time
long filesize = fs.Length;
int i=0;
contentLen = fs.Read(buff, 0, buffLength);
// Till Stream content ends
while (contentLen != 0)
{
Application.DoEvents();
// Write Content from the file stream to the FTP Upload Stream
strm.Write(buff, 0, contentLen);
contentLen = fs.Read(buff, 0, buffLength);
i = i + 1;
//Double percentComp = (i * buffLength) * 100 / filesize;
//ProgressBar1.Value = (int)percentComp;
}
// Close the file stream and the Request Stream
strm.Close();
fs.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Upload Error");
}
}
But here I have the opposite problem - the picture is good, but the file name is corrupted.
I know it is because of the encoding, but I don't know how to make the bytes array have the desired encoding...
Try this bit:
private static void up(string sourceFile, string targetFile)
{
try
{
string ftpServerIP = ConfigurationManager.AppSettings["ftpIP"];
string ftpUserID = ConfigurationManager.AppSettings["ftpUser"];
string ftpPassword = ConfigurationManager.AppSettings["ftpPass"];
////string ftpURI = "";
string filename = "ftp://" + ftpServerIP + "//" + targetFile;
FtpWebRequest ftpReq = (FtpWebRequest)WebRequest.Create(filename);
ftpReq.UseBinary = true;
ftpReq.Method = WebRequestMethods.Ftp.UploadFile;
ftpReq.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
byte[] b = File.ReadAllBytes(sourceFile);
ftpReq.ContentLength = b.Length;
using (Stream s = ftpReq.GetRequestStream())
{
s.Write(b, 0, b.Length);
}
FtpWebResponse ftpResp = (FtpWebResponse)ftpReq.GetResponse();
if (ftpResp != null)
{
MessageBox.Show(ftpResp.StatusDescription);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
You should be using a Stream to read binary files, not a StreamReader. StreamReader is designed to read text files only.
In your first code example, enable binary transfer: FtpWebRequest.UseBinary = true. Otherwise it will convert what it thinks are textual line endings between the various platform conventions (but are actually part of the image).
Your second snippet does it the right way. It uses FileStream, not StreamReader. StreamReader is only suitable for text files.
System.Text.Encoding.UTF8.GetBytes(stream.ReadToEnd());
Don't do this unless your stream's contents are text. Change your function to accept a boolean parameter "binary", and use the latter, working method if that flag is set.
If you have this problem: The requested FTP command is not supported when using HTTP
you need set proxy in Null or Nothing.
ftpReq.Proxy = null;
You can see this blog.
http://mycodetrip.com/2008/10/29/fix-for-error-the-requested-ftp-command-is-not-supported-when-using-http-proxy_118/comment-page-1/#comment-2825
Thanks.