System.Net.FtpClient openwrite不会上传文件,除非我在退出之前插入睡眠
本文关键字:退出 非我 插入 openwrite FtpClient Net 文件 System | 更新日期: 2023-09-27 18:35:39
我正在使用System.Net.FtpClient程序集将文件上传到测试FTP站点。当我运行以下代码时,该文件不会出现在远程位置,除非我按照下面使用 Thread.Sleep(我不想使用):
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 的情况下让它工作吗?我尝试过刷新,关闭流,但这无济于事。
远程 FTP 服务器完全从您的代码异步操作。 根据服务器的配置,它可能会在使文件可用之前执行诸如扫描病毒或其他簿记之类的操作。 除非您直接控制FTP服务器,否则您可能对此无能为力。 即便如此,它也可能需要一些非常深入的配置更改,甚至是不同的软件包。
可能适合您的一件事是在完成上传后"轮询"文件。 创建一个循环,检查文件,等待 1 秒钟,然后重复,直到找到文件或放弃。 Async/Await 模式或来自不同线程的回调可以帮助您摆脱任何 UI 冻结(如果有问题)。
多亏了布拉德利的回答,我设法了一个解决方法:使用 FtpClient.OpenWrite(...) 上传文件,然后我不断检查服务器上的文件大小,这解决了在上传过程中执行代码的问题,应该在上传过程中执行。
然后我遇到了另一个问题,我设法解决了这个问题:在远程FTP服务器上检查上传文件的文件大小时,由于FTP命令(SIZE)并非所有FTP服务器都支持,因此您无法始终通过FtpClient.GetFileSize(...)获取文件大小。解决方案如下:如果 FtpClient.GetFileSize(...) 返回值大于 -1,则 SIZE 命令有效,可以使用。如果函数返回 -1,则只需遍历服务器上指定文件夹中的文件列表。在那里,你会得到一个FtpListItem数组,它有一个名为"Size"的属性。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