2016-02-22 17 views
5

我使用System.Net.FtpClient组件上传文件到测试FTP站点前插入的睡眠。当我运行下面的代码的文件没有出现在远程位置,除非我用了Thread.Sleep按如下(我宁愿不使用):System.Net.FtpClient openwrite犯规上传文件,除非我exitting

using System; 
using System.IO; 
using System.Net; 
using System.Net.FtpClient; 
using System.Security.Cryptography.X509Certificates; 
using System.Threading; 

namespace FtpsUploadTest 
{ 
    /// <summary> 
    /// The ftp publisher. 
    /// </summary> 
    public class FtpPublisher 
    { 
     private readonly FtpsSettings _settings; 
     private readonly IFtpClient _ftpClient; 

     /// <summary> 
     /// Initializes a new instance of the <see cref="FtpPublisher"/> class. 
     /// </summary> 
     public FtpPublisher() 
     { 
      _ftpClient = new FtpClient(); 
      _settings = SettingsReader.GetMySettings(); 
      Init(); 
     } 


     /// <summary> 
     /// The publish. 
     /// </summary> 
     /// <param name="fileToUpload"> 
     /// The input file path. 
     /// </param> 
     public void Publish(string fileToUpload) 
     { 
      var remoteFileName = Path.GetFileName(fileToUpload); 

      Console.WriteLine("FTPS host: {0} remote path: {1}", _settings.FtpsRemoteHost, _settings.FtpsRemotePath); 

      if (!_ftpClient.IsConnected) 
      { 
       _ftpClient.Connect(); 
      } 

      var fullRemotePath = string.Format("{0}/{1}", _settings.FtpsRemotePath, remoteFileName); 

      using (var ftpStream = _ftpClient.OpenWrite(fullRemotePath)) 
      using (var inputStream = new FileStream(fileToUpload, FileMode.Open)) 
      { 
       inputStream.CopyTo(ftpStream); 
       Thread.Sleep(5000); // <------------------- DOESNT WORK IF REMOVE THIS SLEEP!! 
      } 

      Console.WriteLine("File '{0}' published successfully", fileToUpload); 
     } 


     private void Init() 
     { 
      _ftpClient.Host = _settings.FtpsRemoteHost; 
      _ftpClient.Port = _settings.FtpsRemotePort; 
      _ftpClient.DataConnectionConnectTimeout = 60000; 
      _ftpClient.ConnectTimeout = 60000; 
      _ftpClient.Credentials = new NetworkCredential(_settings.FtpsUserId, string.Empty); 
      _ftpClient.DataConnectionType = 0; 

      if (string.IsNullOrEmpty(_settings.CertFile) || string.IsNullOrEmpty(_settings.CertPassword)) 
      { 
       return; 
      } 

      _ftpClient.ClientCertificates.Add(CreateCertificate(_settings.CertFile, _settings.CertPassword)); 
      _ftpClient.EncryptionMode = (FtpEncryptionMode)2; 
      _ftpClient.DataConnectionEncryption = true; 
     } 


     private X509Certificate CreateCertificate(string certFile, string certPassword) 
     { 
      return new X509Certificate(certFile, certPassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet); 
     } 
    } 
} 

任何人都知道我如何能得到它在没有使用Thread.Sleep的情况下工作?我已经尝试冲洗,关闭流,但这并没有帮助。

+0

你使用线程的应用程序?同一个'FtpPublisher'实例是否会被多个线程同时使用? –

+0

即使您在调试器中等待几秒钟,该文件是否完全不可见,以进行编码? –

+0

Joachim,这里没有使用线程。我已经尽可能简化了例子,并能够重现问题。 – user1229458

回答

3

远程FTP服务器完全异步从你的代码行事。根据服务器的配置,它可能会执行诸如扫描病毒或其他簿记操作之前使文件可用。除非您直接控制FTP服务器,否则您可能无法做到这一点。即使这样,它可能需要一些深入的配置更改,甚至是一个不同的软件包。这可能为你工作

一件事是完成上传后,“调查”的文件。创建一个检查文件的循环,等待1秒钟,然后重复,直到找到文件或放弃。 Async/Await模式或来自不同线程的回调可以帮助您摆脱任何UI冻结,如果这是一个问题。

+0

谢谢,我将需要与FTP服务器的所有者检查是否可以证实这一点。他们声称,他们有其他客户端上传失败,但如果这些客户端不立即退出也绝对不会注意到这个问题 – user1229458

+1

我知道这是一个古老的线程,但对于什么是值得... 你有没有得到一个答案回在你的结束? 我遇到了同样的问题,你的睡眠方法确实有帮助。我在我的办公室的Linux机器上建立了一台CrushFTP服务器,并且问题(出现)与ftp服务器一起使用。如果您在写入磁盘之前断开与服务器的连接,则会刷新它的缓冲区。这就是我看起来的样子。 请让我知道你是否发现任何东西。 –

1

感谢布拉德利的回答,我管理一个解决方法:上传文件与FtpClient.OpenWrite(...)之后,我经常检查服务器上的文件大小,解决了上传过程中执行代码的问题应该在它之后执行。

然后我遇到了另一个问题,我管理一个解决方法:在远程FTP服务器上检查上传文件的文件大小时,不能总是通过FtpClient.GetFileSize(...)获取文件大小。由于所有FTP服务器都不支持的FTP命令(SIZE)。该解决方案是以下几点: 如果FtpClient.GetFileSize(...)返回大于-1,大小命令和作品可以使用。 如果该函数返回-1,则可以遍历服务器上指定文件夹中的文件列表。在那里你得到一个FtpListItem数组,它有一个名为“Size”的属性。大小实际上应该返回与FtpClient.GetFileSize(...)相同的值。

示例代码:

const string folderPath = "/media/"; 
string fileName = "image.png"; 
string fullRemotePath = folderPath + fileName; 
string fileToUpload = @"C:\image.png"; 
FtpClient ftpClient = new FtpClient(); 
// start FtpClient connection etc 

FileInfo fileInfo = new FileInfo(fileToUpload); 
long actualFileSize = fileInfo.Length; 
using (var ftpStream = ftpClient.OpenWrite(fullRemotePath)) 
{ 
    using (var inputStream = new FileStream(fileToUpload, FileMode.Open)) 
    { 
     inputStream.CopyTo(ftpStream); 
     //Thread.Sleep(5000); <-- not necessary anymore 
    } 
} 
long fileSizeOnFtp = ftpClient.GetFileSize(fullRemotePath); 
while (fileSizeOnFtp < actualFileSize) 
{ 
    if (fileSizeOnFtp > -1) 
    { 
     fileSizeOnFtp = ftpClient.GetFileSize(fullRemotePath); 
    } 
    else 
    { 
     var ftpListItem = ftpClient.GetListing(folderPath).Where(x => x.Name == fileName).FirstOrDefault(); 
     if (ftpListItem != null) 
     { 
      fileSizeOnFtp = ftpListItem.Size; 
     } 
     else 
     { 
      // the program only could run into this issue if the folder couldn't be listed 
      throw new Exception(); 
     } 
    } 
} 
// execute everything else after ftp upload has finished