FTP Upload in .NET - You ain't need no libraries
Lately I've been asked about doing FTP related stuff in .NET .
There appear to be many "Ftp Clients" out there on CodeProject and other sites.
I really don't get 'em.
They are simple a leaky abstraction on top of straightforward BCL classes.
So what my solution is?
1: public void Upload(string server, int port, string targetFolder, string fileName, string username, string password, bool isActive)
2: {
3: var url = string.Format(
4: "ftp://{0}:{1}{2}/{3}", server, port, targetFolder, fileName)
5: using (var ftp = (FtpWebRequest)WebRequest.Create(url))
6: {
7: ftp.Credentials = new NetworkCredential(username, password);
8: ftp.KeepAlive = false;
9: ftp.UseBinary = true;
10: ftp.Method = WebRequestMethods.Ftp.UploadFile;
11: if (isActive)
12: ftp.UsePassive = false;
13:
14: using (var writer = new BinaryWriter(ftp.GetRequestStream()))
15: writer.Write(File.ReadAllBytes(fileName));
16: }
17: }
This basic notepad code covers most of the functionality in FtpWebRequest. You can easily set Binary/ASCII, Active/Passive, Credentials and whatnot.
Alternatively, in some cases you can just spawn a ftp.exe process with a simple ftp script. Anyway you can rid yourself from unneeded leaky abstractions.
It seems as if writer.Write(File.ReadAllBytes(fileName)); is executed asynchronously. I run the upload method in a BackgroundWorker, and it terminates very quickly without waiting at the writer.Write method. If I put writer.close() after the .Write line then it would wait, however it would timeout if I were uploading a large file.
public static void upload(string f) { if (!File.Exists(f)) throw new Exception("File does not exist."); string url = string.Format("ftp://{0}/{1}", ftpServer, new FileInfo(f).Name); FtpWebRequest fwr = (FtpWebRequest)FtpWebRequest.Create(url); fwr.Credentials = new NetworkCredential(ftpServerUserName, ftpServerPassword); fwr.Method = WebRequestMethods.Ftp.UploadFile; fwr.UseBinary = true; fwr.UsePassive = true; fwr.KeepAlive = false; BinaryWriter writer = new BinaryWriter(fwr.GetRequestStream()); writer.Write(File.ReadAllBytes(f)); writer.Flush(); }How to make this code compatible with uploading large files?
@b, thanks for your input.
the writer should be properly closed to be flushed. It is not that it is Async, just that the underlying Stream is stopped before all buffers are fully flushed. This could be solved by calling .Close (as you did).
If the file is big it might not fit in the client's memory. The code shown here loads the whole file into memory first. it should instead open a Reader from the file and pipe the stream to the BinaryWriter of the ftp stream.
It is also possible that the FTP call is timing out for a combination of large file and slow upload speed. You should be able to increase the timeout on the ftp client (see [http://www.sidesofmarch.com/index.php/archive/2012/04/06/damn-the-documentation-ftpwebrequest-timeout-default-value-is-not-infinite/][1])
Hi. Thanks for code. But I have a question. For me it's not working when I try to upload file to ftps server. I can't understand where to use certificate and passphrase? And its threw an exception 'unable to connect to the remote server'. I think it beacuse of not setting certificate and passphrase. Can you help me? Thanks.