I would really need some help to change from FTP transfer to SFTP. I added some lines in the comment but I'm new to programming and I don't know for sure what I also need to add to fix this problem. The programme works fine but at the moment you transfer your data via FTP. I read some questions here but for now, I couldn't find the right tipp rewrite the program to SFTP.
public class FTP
{
private System.ComponentModel.BackgroundWorker bw = null;
private long filesSize = 0;
private long uploadSize = 0;
private const int bufferLength = 2048;
public FTP()
{
}
public FTP(System.ComponentModel.BackgroundWorker thread, long allFilesSize)
{
bw = thread;
filesSize = allFilesSize;
}
public string ReadUserFile()
{
WebClient req = new WebClient();
req.Credentials = new NetworkCredential("", "");
try
{
byte[] newFileData = req.DownloadData();
return System.Text.Encoding.Default.GetString(newFileData);
}
catch
{
return null;
}
}
public void UploadFile(
string ftpServer, string filePath, string username, string password)
{
//Create SFTP request
//Sftp client = new Sftp();
//client.Connect(hostname);
//client.Login(username, password);
//Create FTP request
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create();
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
//Load the file
//
//Load the file
FileStream stream = File.OpenRead(filePath);
//Upload to Sftp Server
//client.PutFile();
//Upload file
Stream reqStream = request.GetRequestStream();
byte[] buffer = new byte[bufferLength];
int count = 0;
int readBytes = 0;
do
{
readBytes = stream.Read(buffer, 0, bufferLength);
reqStream.Write(buffer, 0, readBytes);
count += readBytes;
if (bw != null)
bw.ReportProgress(CalculateProgress());
}
while (readBytes != 0);
//Disconnect
//client.Disconnect();
stream.Close();
reqStream.Close();
}
private int CalculateProgress()
{
uploadSize += bufferLength;
return (Int32)(uploadSize/(filesSize / 100));
}
public void DeleteFile(
string ftpServer, string filePath, string username, string password)
{
//Create SFTP request
//Sftp client = new Sftp();
//client.Connect(hostname);
//client.Login(username, password);
//Create FTP request
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create();
request.Method = WebRequestMethods.Ftp.DeleteFile;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
}
public string[] GetFileList(
string ftpServer, string username, string password)
{
string[] fileList;
StringBuilder result = new StringBuilder();
FtpWebRequest request;
try
{
request = (FtpWebRequest)FtpWebRequest.Create(new Uri());
request.UseBinary = true;
request.Credentials = new NetworkCredential(username, password);
request.Method = WebRequestMethods.Ftp.ListDirectory;
WebResponse response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string line = reader.ReadLine();
while (line != null)
{
if (line.StartsWith("./"))
line = line.Substring(2, line.Length - 2);
result.Append(line);
result.Append("\n");
line = reader.ReadLine();
}
result.Remove(result.ToString().LastIndexOf('\n'), 1);
reader.Close();
response.Close();
return result.ToString().Split('\n');
}
catch
{
//Error
fileList = null;
return fileList;
}
}
There's no simple way to switch from FTP to SFTP in C#/.NET, if you are currently using .NET FtpWebRequest API.
There's no support for SFTP in .NET framework.
You need 3rd party library: SFTP Libraries for .NET.
That also means that you basically need to scratch your current code and start from the very beginning. Not a single line in your current code would be useful for SFTP with any 3rd party library, as they have very different API to unusual FtpWebRequest.
There are libraries that offer an uniform interface to both FTP and SFTP protocols.
For example WinSCP .NET assembly supports FTP, FTPS, FTPES, SFTP and others (SCP, S3,
WebDAV and WebDAVS) over the same interface.
Though it is not a native .NET assembly. It's rather a thin wrapper over
a console application.
(I'm the author of WinSCP).
Related
Here is a function I have written to download a file from the FTP server. This works when I call this on the Desktop application or console application. But fails and gives the error message when this is in Windows Service or make a console application called from windows scheduler. I need to get a selected files daily. I am trying to automate instead of running manually every day morning.
private void GetFile(string url, string user, string pwd, string folder, string filename
, string destloc, string destfile)
{
try
{
string RemoteFtpPath = url + folder + "/" + filename;
String DestLoc = destloc + destfile;
String Username = user;
String Password = pwd;
Boolean UseBinary = false; // use true for .zip file or false for a text file
Boolean UsePassive = false;
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(RemoteFtpPath);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.KeepAlive = true;
request.UsePassive = UsePassive;
request.UseBinary = UseBinary;
request.Credentials = new NetworkCredential(Username, Password);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
if (File.Exists(DestLoc))
File.Delete(DestLoc);
using (FileStream writer = new FileStream(DestLoc, FileMode.Create))
{
long length = response.ContentLength;
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);
}
}
reader.Close();
response.Close();
}
catch (Exception ex)
{
throw ex;
}
}
By changing the properties solved the issue.
request.KeepAlive = false;
request.UsePassive = true;
request.UseBinary = false;
I've been spending all day trying to figure this one out, but with no luck.
Basically I have a bunch of files and folders, that I want to upload to a FTP server, and everything works great on localhost. But when I deploy it to azure, it stops working. In my head it makes no sense, and my initial thought was it had to do with a firewall, upload timeout or something else.
Do you see anything I am missing in my code, or do I need to do some configuration on azure or my ftp server ?
Edit: I forgot to include the error message:
"The underlying connection was closed: An unexpected error occurred on a receive
Problem Id:System.Net.WebException at simplecms.Models.FtpConn.UploadFile"
public class FtpConn
{
public string UploadCms(string address, string username, string password, string host, bool userftp, string guid)
{
CreateFileUID(guid);
string location;
if (userftp)
{
location = address + "/simplecms/";
host = host + "/simplecms/";
}
else
{
location = address + "/simplecms" + guid + "/";
host = host + "/simplecms" + guid + "/";
}
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(location);
request.Credentials = new NetworkCredential(username, password);
//request.Timeout = -1;
request.UsePassive = true;
request.UseBinary = true;
request.Timeout = 1000000000;
request.KeepAlive = false;
request.ReadWriteTimeout = 1000000000;
request.Method = WebRequestMethods.Ftp.MakeDirectory;
using (var resp = (FtpWebResponse)request.GetResponse())
{
Console.WriteLine(resp.StatusCode);
}
string cmsFolder = "wwwroot/dist/";
string[] cmsFiles = Directory.GetFiles(cmsFolder);
foreach (string file in cmsFiles)
{
string path = Path.GetFullPath(file);
string name = Path.GetFileName(file);
UploadFile(username, password, location, path, name);
}
string[] staticFiles = Directory.GetDirectories(cmsFolder);
string[] subs = Directory.GetDirectories(cmsFolder + "static/");
foreach (string file in staticFiles)
{
CreateDirectory(username, password, location + "/" + Path.GetFileName(file));
}
foreach (string folder in subs)
{
CreateDirectory(username, password, location + "/static/" + Path.GetFileName(folder));
foreach (string subfile in Directory.GetFiles(folder))
{
string path = Path.GetFullPath(subfile);
string name = Path.GetFileName(subfile);
UploadFile(username, password, location + "/static/" + Path.GetFileName(folder) + "/" + Path.GetFileName(subfile), path, "");
}
}
return host;
}
private void UploadFile(string username, string password, string location, string filePath, string fileName)
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(location + fileName);
request.Credentials = new NetworkCredential(username, password);
//request.Timeout = -1;
request.UsePassive = true;
request.UseBinary = true;
request.Timeout = 1000000000;
request.KeepAlive = false;
request.ReadWriteTimeout = 1000000000;
request.Method = WebRequestMethods.Ftp.UploadFile;
FileStream stream = File.OpenRead(filePath);
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
stream.Close();
Stream reqStream = request.GetRequestStream();
reqStream.Write(buffer, 0, buffer.Length);
reqStream.Close();
}
private void CreateDirectory(string username, string password, string newDirectory)
{
try
{
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(newDirectory);
ftpRequest.Credentials = new NetworkCredential(username, password);
//ftpRequest.Timeout = -1;
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = false;
ftpRequest.Method = WebRequestMethods.Ftp.MakeDirectory;
FtpWebResponse ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpResponse.Close();
ftpRequest = null;
}
catch (Exception ex) { Console.WriteLine(ex); }
return;
}
private void CreateFileUID(string uid)
{
string folderName = "wwwroot/dist/";
string[] txtList = Directory.GetFiles(folderName, "*.txt");
foreach (string f in txtList)
{
File.Delete(f);
}
string fileName = "uid.txt";
string pathString = Path.Combine(folderName, fileName);
using (FileStream fs = File.Create(pathString))
{
byte[] SimpleCmsUID = new UTF8Encoding(true).GetBytes(uid);
fs.Write(SimpleCmsUID, 0, SimpleCmsUID.Length);
}
}
}
I am trying to figure out how to get this file uploaded to my ftp server in C#. When it calls getResponse() on ftpwebrequest it is throwing an error that says "550 - access denied". I cannot figure out why. I can connect to the server with Filezilla just fine using the same credentials.
Here is my code that does the connection:
private void UploadFileToFTP(HttpPostedFile file, string server, string user, string pass)
{
string uploadUrl = server + file.FileName;
string uploadFileName = Path.GetFileName(file.FileName);
Stream streamObj = file.InputStream;
Byte[] buffer = new Byte[file.ContentLength];
streamObj.Read(buffer, 0, buffer.Length);
streamObj.Close();
streamObj = null;
try
{
SetMethodRequiresCWD();
FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(uploadUrl);
//ftp.Method = WebRequestMethods.Ftp.MakeDirectory;
ftp.Method = WebRequestMethods.Ftp.UploadFile;
ftp.UsePassive = true;
ftp.Credentials = new NetworkCredential(user, pass);
FtpWebResponse CreateForderResponse = (FtpWebResponse)ftp.GetResponse();
if (CreateForderResponse.StatusCode == FtpStatusCode.PathnameCreated)
{
string ftpUrl = string.Format("{0}/{1}", uploadUrl, uploadFileName);
FtpWebRequest requestObj = FtpWebRequest.Create(ftpUrl) as FtpWebRequest;
requestObj.KeepAlive = true;
requestObj.UseBinary = true;
requestObj.Method = WebRequestMethods.Ftp.UploadFile;
requestObj.Credentials = new NetworkCredential(user, pass);
Stream requestStream = requestObj.GetRequestStream();
requestStream.Write(buffer, 0, buffer.Length);
requestStream.Flush();
requestStream.Close();
requestObj = null;
}
}
catch (WebException e)
{
String status = ((FtpWebResponse)e.Response).StatusDescription;
}
}
OK, I tinkered around with this some more after reading through the comments here. I went into my Kaspersky settings and disabled scanning of port 20 and 21. Boom! File is there. Now it is coming across empty for some reason, so I will investigate that or come back for some help here! :)
I have code set up to do an FTP PUT with a file to an FTP server. First I have a method that checks if the file exists at the target location. Then if it does I have another method that deletes the file. Then I perform the FTP PUT to the target location.
Currently, I'm performing these 3 methods by setting up 3 separate FTP connections to the same server. However, I want to perform all 3 methods with one connection to the server. The reason is because I'm getting the following error after opening multiple connections to same FTP server: "An existing connection was forcibly closed by the remote host."
Here are the 3 functions below. The first method, GetFileFromRemoteServer, is used to see if a file exists on the FTP server at target path. I use regex in some cases to get partial name match, or in other cases just do full name match.
I researched online that someone said it's possible to use the same ftp request object and just perform all methods you want and then close the connection. I tried to see if it works performing multiple methods on same request object and I got this error: This operation cannot be performed after the request has been submitted.
Is there a way to perform all of them using one connection to the server?
Thank you, I really appreciate your help!
public static List<FTPLineResult> GetFileFromRemoteServer(bool isSsl, string username, string password, string fileName, string dir, Regex regexPattern,
bool getSingleFile = false)
{
var output = new List<FTPLineResult>();
var parser = new FTPLineParser();
var isDone = false;
var request = (FtpWebRequest)WebRequest.Create(dir);
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.ConnectionGroupName = ConfigurationManager.AppSettings["ftpConnectionGroup"];
request.KeepAlive = true;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
if (isSsl)
{
request.EnableSsl = true;
}
else
{
request.EnableSsl = false;
}
using (var response = (FtpWebResponse)request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
using (var reader = new StreamReader(responseStream, Encoding.ASCII))
{
while (!isDone && !reader.EndOfStream)
{
var result = parser.Parse(reader.ReadLine());
//if "*" is in file name, which means get partial match, replacing * with real file name content
if (regexPattern != null)
{
if (regexPattern.IsMatch(result.Name.ToLower().Trim()))
{
output.Add(result);
}
}
else if (result.Name.ToLower().Trim() == fileName.ToLower().Trim())
{
output.Add(result);
isDone = true;
}
}
return output;
}
}
}
}
private void DeleteExistingTargetFile()
{
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(_params.FinalFolderTarget);
request.Method = WebRequestMethods.Ftp.DeleteFile;
request.Credentials = new NetworkCredential(_params.Username, _params.Password);
request.UsePassive = true;
request.ConnectionGroupName = ConfigurationManager.AppSettings["ftpConnectionGroup"];
request.KeepAlive = true;
if (_params.IsSsl)
{
request.EnableSsl = true;
}
else
{
request.EnableSsl = false;
}
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
{
var status = response.StatusDescription;
}
}
private void DoFtpPut(Dictionary<StatusEnum, string> statusDict)
{
int buffLength = 2048;
byte[] buff = new byte[buffLength];
System.IO.FileInfo _FileInfo = new System.IO.FileInfo(_params.SourceFilename);
var request = (FtpWebRequest)WebRequest.Create(new Uri(_params.TargetFilename));
request.Method = WebRequestMethods.Ftp.UploadFile;
request.ConnectionGroupName = ConfigurationManager.AppSettings["ftpConnectionGroup"];
request.KeepAlive = true;
request.Credentials = new NetworkCredential(_params.Username, _params.Password);
request.UsePassive = true;
if (_params.IsSsl)
{
request.EnableSsl = true;
}
else
{
request.EnableSsl = false;
}
using (var _Stream = request.GetRequestStream())
{
//read file one chunk at a time in order to avoid out of memory exception
using (var fileStream = _FileInfo.OpenRead())
{
var contentLen = fileStream.Read(buff, 0, buffLength);
while (contentLen != 0)
{
_Stream.Write(buff, 0, contentLen);
contentLen = fileStream.Read(buff, 0, buffLength);
}
}
}
statusDict[StatusEnum.ftpStatus] = Constants.SUCCESS_STATUS;
}
I couldn't figure out a way to do FTPPUT with only one connection using FtpWebRequest class. However, using FtpLib library allowed me to do exactly what I wanted, which was to check if file exists on ftp server target location, if it does then delete it, and then do ftp put, and finally move file to final location using a rename.
Here's where I downloaded ftplib library: ftplib.codeplex.com
Here's the code below:
using (FtpConnection ftp = new FtpConnection(host, _params.Username, _params.Password))
{
try
{
ftp.Open(); /* Open the FTP connection */
ftp.Login(); /* Login using previously provided credentials */
ftp.PutFile(_params.SourceFilename, _params.TargetFilename); /* upload /incoming/file.txt as file.txt to current executing directory, overwrite if it exists */
if (!ftp.DirectoryExists(_params.FinalDir)) /* check that a directory exists */
{
ftp.CreateDirectory(_params.FinalDir);
}
if (ftp.FileExists(_params.FinalLocation))
{
ftp.RemoveFile(_params.FinalLocation);
}
ftp.RenameFile(target, _params.FinalLocation);
statusDict[StatusEnum.ftpStatus] = Constants.SUCCESS_STATUS;
}
catch (Exception ex)
{
statusDict[StatusEnum.ftpStatus] = Constants.ERROR_STATUS;
}
}
The following code is intended to retrieve a file via FTP. However, I'm getting an error with it.
serverPath = "ftp://x.x.x.x/tmp/myfile.txt";
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);
// Read the file from the server & write to destination
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse()) // Error here
using (Stream responseStream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(responseStream))
using (StreamWriter destination = new StreamWriter(destinationFile))
{
destination.Write(reader.ReadToEnd());
destination.Flush();
}
The error is:
The remote server returned an error: (550) File unavailable (e.g., file not found, no access)
The file definitely does exist on the remote machine and I am able to perform this ftp manually (i.e. I have permissions). Can anyone tell me why I might be getting this error?
I know this is an old Post but I am adding here for future reference. Here is a solution that I found:
private void DownloadFileFTP()
{
string inputfilepath = #"C:\Temp\FileName.exe";
string ftphost = "xxx.xx.x.xxx";
string ftpfilepath = "/Updater/Dir1/FileName.exe";
string ftpfullpath = "ftp://" + ftphost + ftpfilepath;
using (WebClient request = new WebClient())
{
request.Credentials = new NetworkCredential("UserName", "P#55w0rd");
byte[] fileData = request.DownloadData(ftpfullpath);
using (FileStream file = File.Create(inputfilepath))
{
file.Write(fileData, 0, fileData.Length);
file.Close();
}
MessageBox.Show("Download Complete");
}
}
Updated based upon excellent suggestion by Ilya Kogan
Easiest way
The most trivial way to download a binary file from an FTP server using .NET framework is using WebClient.DownloadFile:
WebClient client = new WebClient();
client.Credentials = new NetworkCredential("username", "password");
client.DownloadFile(
"ftp://ftp.example.com/remote/path/file.zip", #"C:\local\path\file.zip");
Advanced options
Use FtpWebRequest, only if you need a greater control, that WebClient does not offer (like TLS/SSL encryption, progress monitoring, ascii/text transfer mode, resuming transfers, etc). Easy way is to just copy an FTP response stream to FileStream using Stream.CopyTo:
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 ftpStream = request.GetResponse().GetResponseStream())
using (Stream fileStream = File.Create(#"C:\local\path\file.zip"))
{
ftpStream.CopyTo(fileStream);
}
Progress monitoring
If you need to monitor a download progress, you have to copy the contents by chunks yourself:
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 ftpStream = request.GetResponse().GetResponseStream())
using (Stream fileStream = File.Create(#"C:\local\path\file.zip"))
{
byte[] buffer = new byte[10240];
int read;
while ((read = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
{
fileStream.Write(buffer, 0, read);
Console.WriteLine("Downloaded {0} bytes", fileStream.Position);
}
}
For GUI progress (WinForms ProgressBar), see:
FtpWebRequest FTP download with ProgressBar
Downloading folder
If you want to download all files from a remote folder, see
C# Download all files and subdirectories through FTP.
This paragraph from the FptWebRequest class reference might be of interest to you:
The URI may be relative or absolute.
If the URI is of the form
"ftp://contoso.com/%2fpath" (%2f is
an escaped '/'), then the URI is
absolute, and the current directory is
/path. If, however, the URI is of the
form "ftp://contoso.com/path", first
the .NET Framework logs into the FTP
server (using the user name and
password set by the Credentials
property), then the current directory
is set to /path.
I had the same issue!
My solution was to insert the public_html folder into the download URL.
Real file location on the server:
myhost.com/public_html/myimages/image.png
Web URL:
www.myhost.com/myimages/image.png
private static DataTable ReadFTP_CSV()
{
String ftpserver = "ftp://servername/ImportData/xxxx.csv";
FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpserver));
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream responseStream = response.GetResponseStream();
// use the stream to read file from FTP
StreamReader sr = new StreamReader(responseStream);
DataTable dt_csvFile = new DataTable();
#region Code
//Add Code Here To Loop txt or CSV file
#endregion
return dt_csvFile;
}
I hope it can help you.
public void download(string remoteFile, string localFile)
{
private string host = "yourhost";
private string user = "username";
private string pass = "passwd";
private FtpWebRequest ftpRequest = null;
private FtpWebResponse ftpResponse = null;
private Stream ftpStream = null;
private int bufferSize = 2048;
try
{
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(host + "/" + remoteFile);
ftpRequest.Credentials = new NetworkCredential(user, pass);
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpStream = ftpResponse.GetResponseStream();
FileStream localFileStream = new FileStream(localFile, FileMode.Create);
byte[] byteBuffer = new byte[bufferSize];
int bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);
try
{
while (bytesRead > 0)
{
localFileStream.Write(byteBuffer, 0, bytesRead);
bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);
}
}
catch (Exception) { }
localFileStream.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
}
catch (Exception) { }
return;
}
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverPath);
After this you may use the below line to avoid error..(access denied etc.)
request.Proxy = null;
FYI, Microsoft recommends not using FtpWebRequest for new development:
We don't recommend that you use the FtpWebRequest class for new development. For more information and alternatives to FtpWebRequest, see WebRequest shouldn't be used on GitHub.
The GitHub link directs to this SO page which contains a list of third-party FTP libraries, such as FluentFTP.