2016-02-22 4 views
5

System.Net.FtpClientアセンブリを使用してテストFTPサイトにファイルをアップロードしています。私は以下のコードを実行すると、私は(私が使用することを希望されないもの)以下のとおりのThread.sleepを使用しない限り、ファイルは、リモートの場所に表示されません。System.Net.FtpClient openwriteは、終了する前にスリープを挿入しない限りファイルをアップロードしません。

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

ヨアヒム、ここでスレッドは使用されていません。私はできるだけシンプルな例を作り、問題を再現できました。 – user1229458

答えて

3

リモートFTPサーバーは、コードから完全に非同期で動作しています。サーバーの構成によっては、ファイルを使用可能にする前にウイルスやその他の簿記をスキャンするなどの処理を行う場合があります。 FTPサーバーを直接制御しない限り、これについて何もできないことがあります。それでもかなり深い設定変更、あるいは別のソフトウェアパッケージが必要になるかもしれません。

あなたがうまくいくかもしれないことの1つは、アップロードを完了した後でファイルを「ポーリング」することです。ファイルをチェックして1秒間待ってから、ファイルが見つかるまで、またはフォローアップするまで繰り返します。 Async/Awaitパターン、または別のスレッドからのコールバックは、問題が発生した場合にUIのフリーズを取り除くのに役立ちます。

+0

これを確認できるのであれば、FTPサーバーの所有者に確認する必要があります。彼らは彼らが他のクライアントを正常にアップロードしていると主張しますが、それらのクライアントがすぐに終了しない場合、彼らは問題に気付くことはありません – user1229458

+1

私はこれが古いスレッドだと知っていますが、それは何の価値があるのでしょうか... あなたは終わり? 私は同じ問題を抱えていました。あなたの睡眠方法が実際に助けになりました。私は私のオフィスのLinuxボックスにCrushFTPサーバーを構築しました。問題はFTPサーバーにあります。ディスクに書き込む前にサーバから切断すると、バッファがフラッシュされます。それは私に似ています。 何かを発見した場合はお知らせください。 –

1

私は回避策を管理しました:FtpClient.OpenWrite(...)を使用してファイルをアップロードした後、サーバー上のファイルサイズを常に確認し、アップロードプロセス中にコードが実行されるという問題を解決しました後に実行する必要があります。

次に、リモートFTPサーバー上のアップロードファイルのファイルサイズを確認すると、FtpClient.GetFileSize(...)を使用してファイルサイズを取得できない場合がありました。すべてのFTPサーバーでサポートされていないFTPコマンド(SIZE)が原因です。解決方法は次のとおりです。 FtpClient.GetFileSize(...)の戻り値が-1より大きい場合、SIZEコマンドが機能して使用できます。 この関数が-1を返す場合は、サーバー上の指定されたフォルダにあるファイルのリストをたどることができます。そこには、 "Size"というプロパティを持つ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 
関連する問題