.NET FTP Upload file and preserve original date time - c#

We have a Windows 2008 R2 web server with FTP over SSL. This app uses .NET 4.5 and when I upload files, the date/time on the file changes to the current date/time on the server. Is there a way to have the uploaded file preserve the original (last modified) date?
Here is what I have:
FtpWebRequest clsRequest = (FtpWebRequest)WebRequest.Create(FTPFilePath);
clsRequest.EnableSsl = true;
clsRequest.UsePassive = true;
clsRequest.Credentials = new NetworkCredential(swwwFTPUser, swwwFTPPassword);
clsRequest.Method = WebRequestMethods.Ftp.UploadFile;
Byte[] bFile = File.ReadAllBytes(LocalFilePath);
Stream clsStream = clsRequest.GetRequestStream();
clsStream.Write(bFile, 0, bFile.Length);
clsStream.Close();
clsStream.Dispose();
clsRequest = null;

There's really no standard way to update timestamp of a remote file over an FTP protocol. That's probably why the FtpWebRequest does not support it.
There are two non-standard ways to update the timestamp. Either a non-standard MFMT command:
MFMT yyyymmddhhmmss path
or a non-standard use of (otherwise standard) MDTM command:
MDTM yyyymmddhhmmss path
But the FtpWebRequest does not allow you to send a custom command either.
See for example How to send arbitrary FTP commands in C#.
So you have to use a 3rd party FTP library.
For example WinSCP .NET assembly preserves a timestamp of an uploaded file by default.
// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Ftp,
HostName = "example.com",
UserName = "user",
Password = "mypassword",
};
using (Session session = new Session())
{
// Connect
session.Open(sessionOptions);
// Upload
session.PutFiles(#"c:\toupload\file.txt*", "/home/user/").Check();
}
See a full example.
Note that WinSCP .NET assembly is not a native .NET assembly. It's rather a thin .NET wrapper around a console application.
(I'm the author of WinSCP)

I know that we can assign file attributes:-
//Change the file created time.
File.SetCreationTime(path, dtCreation);
//Change the file modified time.
File.SetLastWriteTime(path, dtModified);
If you can extract the original date before you save it to the server, then you can change file attributes....something like this:-
Sftp sftp = new Sftp();
sftp.Connect(...);
sftp.Login(...);
// upload the file
sftp.PutFile(localFile, remoteFile);
// assign creation and modification time attributes
SftpAttributes attributes = new SftpAttributes();
System.IO.FileInfo info = new System.IO.FileInfo(localFile);
attributes.Created = info.CreationTime;
attributes.Modified = info.LastWriteTime;
// set attributes of the uploaded file
sftp.SetAttributes(remoteFile, attributes);
I hope this points you in the right direction.

This is an older question, but I will add my solution here. I used an approach similar to the solution proposed by #Martin Prikryl, using the MDTM command. His answer shows the DateTime format string as yyyymmddhhmmss which is incorrect since it does not correctly handle the month and 24 hour time format. In this answer I corrected this issue and provided a full solution using C#.
I used the FluentFTP library which handles many other aspects of working with an FTP through C# very well. To set the modified time, this library does not support it but it has an Execute method. Using the FTP command MDTM yyyyMMddHHmmss /path/to/file.txt will set the modified time of the file.
NOTE: in my instance I needed to use the universal time, which may be the case for you.
The code below shows how to connect to the FTP and set the last modified time using the Execute method and sending the MDTM command.
FtpClient client = new FtpClient("ftp-address", "username", "password");
client.Connect();
FtpReply reply = client.Execute($"MDTM {DateTime.UtcNow.ToString("yyyyMMddHHmmss")} /path/to/file.txt");

Related

Download files using FluentFTP

I am trying to implement FTP transfer using FluentFTP in C#. Getting a directory listing is very easy, but I am stuck on downloading files.
I found one article that has an example in its comments here but it won't compile because I cannot find where the class FtpFile comes from.
Does anybody have an example of how tocan I download a file from an ftp server using FluentFTP ?
EDIT: I found some examples here https://github.com/hgupta9/FluentFTP But there is no example on how to actually download a file.
In the this article Free FTP Library there is an example but it does not compile. This is the example
FtpClient ftp = new FtpClient(txtUsername.Text, txtPassword.Text, txtFTPAddress.Text);
FtpListItem[] items = ftp.GetListing();
FtpFile file = new FtpFile(ftp, "8051812.xml"); // THIS does not compile, class FtpFile is unknown
file.Download("c:\\8051812.xml");
file.Name = "8051814.xml";
file.Download("c:\\8051814.xml");
ftp.Disconnect();
EDIT: The solution
The article I found contained an example that set me in the wrong direction.
It seems there was once a Download method but that is gone long ago now.
So the answer was to let that go and use the OpenRead() method to get a stream and than save that stream to a file.
There are now DownloadFile() and UploadFile() methods built into the latest version of FluentFTP.
Example usage from https://github.com/robinrodricks/FluentFTP#example-usage:
// connect to the FTP server
FtpClient client = new FtpClient();
client.Host = "123.123.123.123";
client.Credentials = new NetworkCredential("david", "pass123");
client.Connect();
// upload a file
client.UploadFile(#"C:\MyVideo.mp4", "/htdocs/big.txt");
// rename the uploaded file
client.Rename("/htdocs/big.txt", "/htdocs/big2.txt");
// download the file again
client.DownloadFile(#"C:\MyVideo_2.mp4", "/htdocs/big2.txt");

C# - Download files from FTP which have higher last-modified date

I have an FTP server with some files. I have the same files in in a local directory (in C:\).
When I'll run the program, I'd like it searches all files in the FTP server that have a last-modified timestamp later than the same file (equal name) in local directory and download all files founded.
Can someone give me a help or a tip, please? I'll appreciate all answers!
Unfortunately, there's no really reliable and efficient way to retrieve timestamps using features offered by the .NET framework, as it does not support the FTP MLSD command. The MLSD command provides listing of remote directory in a standardized machine-readable format. The command and the format is standardized by the RFC 3659.
Alternatives you can use that are supported by the .NET framework:
the ListDirectoryDetails method (the FTP LIST command) to retrieve details of all files in a directory and then you deal with FTP server specific format of the details (*nix format similar to ls *nix command is the most common, drawback is that the format may change over time, as for newer files "May 8 17:48" format is used and for older files "Oct 18 2009" format is used).
Examples:
DOS/Windows format: C# class to parse WebRequestMethods.Ftp.ListDirectoryDetails FTP response
*nix format: Parsing FtpWebRequest ListDirectoryDetails line
the GetDateTimestamp method (an FTP MDTM command) to individually retrieve timestamps for each file. An advantage is that the response is standardized by the RFC 3659 to YYYYMMDDHHMMSS[.sss]. A disadvantage is that you have to send a separate request for each file, what can be quite inefficient.
const string uri = "ftp://example.com/remote/path/file.txt";
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri);
request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Console.WriteLine("{0} {1}", uri, response.LastModified);
Alternatively you can use a 3rd party FTP client implementation that supports the modern MLSD command.
For example the WinSCP .NET assembly supports that.
You can use the Session.ListDirectory or the Session.EnumerateRemoteFiles methods and read the RemoteFileInfo.LastWriteTime of the files in returned collection.
Or even easier, you can use the Session.SynchronizeDirectories to have the library automatically download (synchronize) the modified files:
// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Ftp,
HostName = "ftp.example.com",
UserName = "user",
Password = "mypassword",
};
using (Session session = new Session())
{
// Connect
session.Open(sessionOptions);
// Synchronize files
var localPath = #"d:\www";
var remotePath = "/home/martin/public_html";
session.SynchronizeDirectories(
SynchronizationMode.Local, localPath, remotePath, false).Check();
}
WinSCP GUI can generate a code template for you.
(I'm the author of WinSCP)
List all files : https://msdn.microsoft.com/en-us/library/ms229716(v=vs.110).aspx
Read date : https://msdn.microsoft.com/en-us/library/system.net.ftpwebresponse.lastmodified(v=vs.110).aspx

WinSCP SFTP connection error

While accessing my remote server, from SFTP, I am constantly getting this error
Connection has been unexpectedly closed. Server sent command exit status 0
I have filled same credentials in WinSCP, it is working fine. Where am I lacking?
Also, instead of .ppk file I am using "ssh-rsa 1024 #######################" in my keyfile column in my project's UI.
Thank You,
Pranay
For the problem above, I found that while attempting to "open the session" i.e session.Open(sessionOptions), it will through the exception as the server was not authenticating it.
As my task was to "password less winscp login", i.e i must have to provide:-
1.".ppk" file that is "puTTy private key".
2. Its "ssh key fingerprint".
After all day debugging, finally found that my version of winsscp.dll was old thus was not providing me the [metadata] inbuild properties as
1. SshPrivateKeyPath -> location of our ".ppk" file.
2. SshHostKeyFingerprint
3. passphrase -> only for one time login.
By updating the new version and above now I am able to open session, without any error.
Thank you.
I've also faced the same problem , when i first tried to execute the code mentioned at the below link.
https://winscp.net/eng/docs/library#example
Googled it a lot but i couldn't find any solution regarding the same.
Finally the following i relalized that i'm missing the portnumber in the example
Adding the port number field to my code solved the issue.
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = "11.22.33.44",
PortNumber = 2222, /* This is cause of the issue i was facing*/
UserName = "abcdef",
Password = "ghijklmnop",
SshHostKeyFingerprint = "ssh-rsa 2048 aa:bb:cc:dd:ee:ff:gg:hh:ii:jj:kk:ll:mm:nn:oo:pp"
};
If you can connect with WinSCP GUI, but not with .NET assembly, when running both in the same environment (computer), you have most probably missed some settings (like a port number or a host key fingerprint, as the other answers show).
The easiest solution is to have WinSCP GUI generate a code template for you based on its working settings.
If you are running the code on a different machine, check WinSCP FAQ Why does WinSCP not work in a new environment (operating system, machine, user account, network), when it works for me in a different environment already?
While the article is not explicitly about .NET assembly, but about WinSCP in general, it covers issues that you can face with the assembly too.

c# FTP to FileZilla Server file name save issue

Whenever I use this code it uploads the jpeg, but the jpegs name is STOR with no extension on the server.
Any idea as to why this happens or how I change the file name when saving from my C# desktop application to my FileZilla FTP Server??
Here is the basic code, the names have been changes to protect the innocent ;)
WebClient client = new WebClient();
client.Credentials = new NetworkCredential("username", "password");
client.BaseAddress = "ftp://mysite.com";
client.UploadFile(WebRequestMethods.Ftp.UploadFile, "C:\mypics\pic1.jpg");
Try
client.UploadFile(remoteName, WebRequestMethods.Ftp.UploadFile , #"C:\mypics\pic1.jpg");
WebRequestMethods.Ftp.UploadFile is a string whose value happens to be STOR so the compiler is assuming your are using the client.UploadFile(remoteName, localName) overload which is why your file is named STOR
#sgmoore answered the question. You need just use method correctly:
client.UploadFile("pic1.jpg", "C:\mypics\pic1.jpg");
first argument is remote file name, second is path to local file.
You can also try some other ftp client implementations in .net (anyway FTP is implemented badly in .NET standard library), I've used ftplib and it's working good.

SFTP with .NET 3.5

I need to connect to an SFTP server to download and upload files using C#/.NET 3.5.
Does the .NET 3.5 framework provide any built-in tools/mechanisms/libraries to connect to an SFTP server to download and upload files?
There are commercial solutions:
http://www.rebex.net/sftp.net/
http://www.enterprisedt.com/products/edtftpnetpro/overview.html
...and free:
http://www.tamirgal.com/blog/page/SharpSSH.aspx
I personally have no experience with any of them.
There's no support for SFTP in .NET framework, in any version.
The answer by Sanj shows how to use WinSCP by driving its console application. While that's indeed possible, where actually WinSCP .NET assembly that does it for a developer, giving him/her native .NET interface to the WinSCP scripting.
There's even a WinSCP NuGet package.
A trivial SFTP upload C# example:
// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = "example.com",
UserName = "user",
Password = "mypassword",
SshHostKeyFingerprint = "ssh-rsa 2048 xxxxxxxxxxx...="
};
using (Session session = new Session())
{
// Connect
session.Open(sessionOptions);
// Upload files
session.PutFiles(#"d:\toupload\*", "/home/user/").Check();
}
And the same for VB.NET:
' Setup session options
Dim sessionOptions As New SessionOptions
With sessionOptions
.Protocol = Protocol.Sftp
.HostName = "example.com"
.UserName = "user"
.Password = "mypassword"
.SshHostKeyFingerprint = "ssh-rsa 2048 xxxxxxxxxxx...="
End With
Using session As New Session
' Connect
session.Open(sessionOptions)
' Upload files
session.PutFiles("d:\toupload\*", "/home/user/").Check()
End Using
There are lot of other examples in both languages (and more).
You can have WinSCP GUI generate an SFTP code template, like above, for you, including C#, VB.NET and PowerShell.
As mentioned above, the assembly is just a wrapper around WinSCP scripting, so it's not a completely native .NET code. As such it does not fit all use cases in .NET framework. It is mostly suitable for automating tasks, not for developing GUI or web applications.
For a fully native .NET SFTP library, see SSH.NET, which is strangely not mentioned in any answer yet.
(I'm the author of WinSCP)
No, .NET doesn't ship with any SFTP libraries. However, WinSCP is a free utility you can download. I've used it before to download information from a PayPal report server.
It has a nice command line setup for you to automate the download / upload of files too. So from my .NET app, you just invoke the process with the specific arguments and wait until it completes.
I prefer WinSCP. It's free and I've tried it before, it works perfectly. If you download the COM file and you could do something like below:
NOTE: I'm passing the params from ini.
const string logname = "log.xml";
string username = ini.IniReadValue("sftp", "Username");
string password = ini.IniReadValue("sftp", "Password");
string remotehost = ini.IniReadValue("sftp", "Remote Host");
string dloadpath = ini.IniReadValue("Download", "Local Path");
Process winscp = new Process();
winscp.StartInfo.FileName = #ini.IniReadValue("winscp", "compath");
winscp.StartInfo.Arguments = "/log=" + logname;
winscp.StartInfo.UseShellExecute = false;
winscp.StartInfo.RedirectStandardInput = true;
winscp.StartInfo.RedirectStandardOutput = true;
winscp.StartInfo.CreateNoWindow = true;
try
{
winscp.Start();
lblconfirm.Text = "Status: WinSCP Started Successfully";
}
catch (Exception ex)
{
writeLog("from PutSFTP: Could not run the WinSCP executable " + winscp.StartInfo.FileName + Environment.NewLine + ex.Message);
}
winscp.StandardInput.WriteLine("option batch abort");
winscp.StandardInput.WriteLine("option confirm off");
winscp.StandardInput.WriteLine("open sftp://" + username + ":" + password + "#" + remotehost);
winscp.StandardInput.WriteLine("cd " + ini.IniReadValue("Download", "Remote Path"));
winscp.StandardInput.WriteLine(#"get " + "/" + ini.IniReadValue("Download", "Remote Path") + "/*" + ini.IniReadValue("Download", "FileType") + " " + ini.IniReadValue("Download", "Local Path"));
winscp.StandardInput.Close();
string output = winscp.StandardOutput.ReadToEnd();
lblconfirm.Text = "Download Success! Check logs for moe info";
winscp.WaitForExit();
The framework does not provide SFTP support.
IIS 7.x (which comes with Windows server 2008 or Windows 7) supports only FTPs, not sFTP natively (explanation see update below) - however there are server solutions like this one available for the sFTP protocol.
If you require an sFTP client, Microsoft has not provided any support so far. But I've made very good expericence with a 3rd party .NET component named wodSFTP.NET, which is a sFTP client.
Here you can find the product & documentation: wodSFTP.NET.
Examples and online-documentation can be downloaded without any charge or registration from them.
Note that you can choose whether you buy the version without or with Sourcecode in C#. They have a SSH component as well. Examples are always available (regardless of the version you choose) in C# and VB.NET.
Example (from the website www.weonlydo.com, converted to C#):
var wodSFTP1 = new WeOnlyDo.Client.SFTP();
// Authenticate with server using hostname, login, password.
wodSFTP1.Hostname = "your_hostname";
wodSFTP1.Login = "your_login";
wodSFTP1.Password = "your_password";
wodSFTP1.Blocking = True; // Use synchronous connections
wodSFTP1.Connect();
wodSFTP1.GetFile("c:\", "/home/somepath/somefile.txt");
This example uses blocking (synchronous) mode. Note that you can also use the component asynchronously - in this case events will be fired and you can write event handlers to react on them.
Note that this example does not use a key to authenticate, but of course this is also supported (you can use key-based authentication, password-based authentication or both).
Update: FTPs and sFTP are different protocols. Please follow the links for an explanation.
Since there is no native support, uou can search in Google for other, commercial, components, just type something like 'SFTP components .NET'

Categories