如何FTP不断传入的文件

时间:2011-05-27 14:18:32

标签: c# multithreading ftp bandwidth createfile

好的,这是情况......我有一个应用程序,每秒生成大约8个文件。每个文件是19-24kb。这每分钟产生大约10到11 MB。这个问题不是关于如何ftp,因为我已经有了这个解决方案......问题更多是关于如何跟上数据流(在大多数情况下只有2mb上传带宽,除非我前往客户端站点有一个大管道)。我不在乎ftp需要更长的时间来传输流量,但是我想知道是否有人知道如何批处理文件来移动它们以便在ftp进程完成时它将删除它传输的那些文件然后转到下一批。这就是我的想法:

应用程序的多线程,第一个线程运行应用程序,第二个线程是一个计时器,每隔“N”分钟创建一个文本文件,其中包含在该时间跨度内创建的所有文件。 Stream读取文件并将文本中的文件移动到另一个位置(可能创建一个临时文件夹)然后ftp这些文件,然后删除文件,文件夹和文本文件...同时,正在编写更多文本文件和temp正在创建的文件夹这听起来可行吗?我会采取任何建议,任何人都有建议,只是寻找最快和最可靠的道路。

请不要问看代码,考虑到我们正在使用假设,没有理由看到它。

7 个答案:

答案 0 :(得分:4)

我会创建一个服务,并使用FileSystemWatcher,System.Threading.Timer或两者将传入的文件添加到并发集合中(如果文件缓冲区溢出,FileSystemWatcher可能会丢失文件,因此最好让计时器选择任何错过的文件)。当文件进来时,我会将它们移动到一个单独的文件夹中,并使用.NET 4.0任务处理它们。然后,我将在原始任务的继续步骤中进行任何必要的后处理。您可以使用继续步骤来处理成功时发生的任何故障和不同的继续步骤。这些任务中的每一个都将启动线程池中的一个线程,并为您管理。

以下是来自OnlyOnFaulted延续任务的http://msdn.microsoft.com/en-us/library/dd997415.aspx的示例。您可以有第二个继续任务,只有在成功时才会运行。

var task1 = Task.Factory.StartNew(() =>
{
    throw new MyCustomException("Task1 faulted.");
})
.ContinueWith((t) =>
    {
        Console.WriteLine("I have observed a {0}",
            t.Exception.InnerException.GetType().Name);
    },
    TaskContinuationOptions.OnlyOnFaulted);

答案 1 :(得分:1)

如果不知道为什么需要将所有工作保留在单个应用程序中并处理线程复杂性的任何更多详细信息,可以争论保留生成文件的部分以及将文件FTP文件放在单独的应用程序中的部分。

责任分离。确保每个应用程序只执行一项工作,并且正确而快速地完成。

生成文件的一个服务器或应用程序(桌面/网络)。

另一个服务,它监视文件夹并将任何传入的文件移动到临时文件中,执行它需要做的事情,FTP和删除。

看到我不知道您的设置以及从哪里获取文件的内容,将其写在一个应用程序中可能是您​​建议的最佳选择。

基本上是为了回答你的问题。是的,它确实可行,你想做什么。 您如何实施它以及您对实施的满意程度取决于您。

如果您在实施过程中陷入困境,请随时在新威胁中发布任何问题,并提供有关如何实施特定功能以及您遇到的问题的一些代码示例。

在此之前,假设您认为能够管理您需要达到的目标的任何方法都是完全有效的。

修改

看到你说你已经有了生成文件的应用程序,你已经有了一个解决方案,FTP意味着使用2个单独的应用程序听起来更合理。

然后您需要的是围绕FTP解决方案和快乐的日子提供服务。 如果文件已经生效,则无需与生成文件的原始应用程序进行互操作。

为什么要冒险破坏它,除非你必须在其中添加fTP功能,否则你别无选择。

答案 2 :(得分:1)

我在以前的工作中做过类似的事情。我在某个文件夹上有一个外部进程转储文件。这是我遵循的算法:

  1. 在转储文件的源目录上运行FileSystemWatcher
  2. 找到新文件后,按日期的升序处理目录中的所有文件。 (在你的情况下ftp文件)
  3. 处理完文件后,我将它们移到Processed目录(在这种情况下,你可以删除它们)
  4. 需要考虑的事项:

    1. 我可以拥有多少个打开的ftp连接/处理线程
    2. FileSystemWatcher可以并且将在处理另一个文件时引发事件。如何处理/将其发送到适当的线程

答案 3 :(得分:0)

如果生产者太快,您需要在文件的生产者和使用者(FTP主机)之间插入一个队列,以便能够缓冲文件。这需要某种形式的多线程甚至多个过程。

您提出了一个解决方案,其中队列是文件系统,这很可能,但在许多情况下并不理想。您必须正确锁定以避免传输半填充或空文件等。如果您决定使用文件系统,我的经验是FileSystemWatcher不能用于此目的。使用计时器来运行任务说每秒接收新文件都更可靠。

其他队列技术可能是内存中队列(但您必须考虑如何处理崩溃),私有Microsoft Message Queue或SQL Server Broker队列。最佳解决方案在很大程度上取决于您的要求。

FTP实际上并不是事务性的,您可能决定使用非事务性的队列(MSMQ和SQL Server Broker都是事务性的),但您仍应尝试围绕文件所在的事务概念构建应用程序。创建,排队和交付。如果无法交付,则将其留在队列中,稍后重试交付。如果它不能排队,那么生产者应该重试排队等等。你不希望文件永远不会被传递或被传递两次。

从您的问题中不清楚您将如何使用FTP,但我建议您使用开源或商业库直接从您的应用程序中使用FTP,而不是炮轰{{1} }。这将使您的应用程序能够智能地保持FTP连接处于打开状态,以避免过多的重新连接等。

您还应该考虑如何处理队列过于庞大的情况。一种选择可能是停止生产者,直到队列大小减少到阈值以下。

答案 4 :(得分:0)

  1. 启动一个每秒触发一次的计时器。
  2. 在计时器的已用事件处理程序中,停止计时器。
  3. 获取传入目录中所有文件的列表。
  4. 尝试专门打开每个文件。这可以防止您读取仍在写入的文件。
  5. 将每个文件复制到暂存目录,并将其从传入目录中删除。
  6. 移动列表中的所有文件后,通过FTP发送暂存目录中的文件。
  7. 将FTP文件删除后,将其从暂存目录中删除。
  8. 启动计时器。
  9. 计时器的已运行处理程序在线程池上为您运行,您应该需要任何更高级的线程管理。由于您的主要约束是您的FTP带宽,因此在上传文件之前,使用其他线程执行任何其他操作几乎没有什么优势。

    此方法可在系统崩溃时为您提供保护。在下一个周期中拾取暂存目录中未发送的文件。传入目录中的文件也是如此。

    如果您的FTP接收方可以处理压缩文件,您可以通过压缩暂存目录的内容并将其作为一个文件发送来提高吞吐量。

答案 5 :(得分:0)

我会使用BlockingCollections建立一个线程链。

一个生产者线程使用计时器或FileSystemWatcher等读取可用文件,并将它们存储在BlockingCollection中。它还将文件存储在列表中,以确保它们只添加一次。

var availableFiles = new BlockingCollection<string>();
var processedFiles = new BlockingCollection<string>();
var newFiles = new HashSet<string>();

...
lock (newFiles) {
    foreach (var file in Directory.GetFiles())
        if (!newFiles.Contains(file)) {
            availableFiles.Add(file);
            newFiles.Add(file);
        }
}

一个或多个ftp线程发送文件,然后将它们放入已处理的集合

foreach (var file in availableFiles.GetConsumingEnumerable()) {
   SendFileOverFtp(file);
   processedFiles.Add(file);
}

一个清理已处理文件的线程

foreach (var file in processedFiles.GetConsumingEnumerable()) {
    lock (newFiles) {
       File.Delete(file);
       newFiles.Remove(file);
    }
}

另一种方法是让生产线程也将文件读入内存并删除它们。在这种情况下,您可以跳过最后一个阶段和newFiles集合

答案 6 :(得分:0)

作为这种情况下的FTP服务器所有者,我还要求您找到一种尽可能保持登录的方法。

登录/关闭通常比单个文件传输更“昂贵”(在计算,配置阻止等方面)。