2011-05-27 50 views
3

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

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

请不要问看到代码,没有理由看它考虑到我们与hypotheticals工作。

+0

使用两个线程是要走的路。 – 2011-05-27 14:24:09

+0

此外,我也是一个困惑。该主题中的问题是“如何FTP不断传入文件”,但你说“这个问题不是关于如何FTP,因为我已经有了这个解决方案......”。在考虑实际问题的情况下更新主题可能是一个好主意? – Nope 2011-05-27 14:42:19

+0

纯粹从带宽的角度来看,压缩你的文件。 GZip可以定期在文本上获得70-85%的压缩比。 – Brad 2011-05-27 14:52:28

回答

1

Wihtout真的知道为什么你需要把所有的工作在一个单一的应用程序和处理线程的复杂性的更多细节,人们可以说,以保持生成文件的一部分,FTPS文件的一部分在不同的应用程序

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

一个Serivce或应用程序(桌面/网络有史以来)生成的文件。

该款腕表的文件夹,并会将所有传入的文件到一个临时的Filder,做的事情需要做,FTPS和删除其他服务。

眼看我不知道你的设置以及从何处获取内容为您的文件,在一个单一的应用程序编写它可能是你究竟是如何建议的最佳选择。

基本上可以解答你的问题。是的,这听起来可行,你想做什么。 你如何实现它,你对实现的满意程度取决于你。

如果得到实施过程中的某个地方卡住,随时与一些代码示例一个新的威胁后你如何有一个具体的功能实现,问题是你遇到的任何问题。

在此之前,假设,任何你感觉能够管理你需要实现的方法都是完全有效的。

编辑

看到你说你已经有生成文件完成,你已经有了这Tilt点数是指使用2个单独的应用程序听起来更合理的解决方案中的应用。

所有你需要的是围绕FTP解决方案和快乐的日子。 没有必要与生成文件的原始应用程序相互作用,如果它已经在工作。

为什么冒险打破它,除非你必须添加fTP功能,你别无选择。

+0

ftp prtion是我一年前写的一个类,我添加到需要执行ftp的应用程序中...我只是向该类发送一个文件路径字符串,然后...瞧。 – 2011-05-27 18:32:47

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); 
+0

感谢科尔......我其实从来没有想过这件事。 – 2011-05-27 18:35:48

1

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

  1. 对其中的文件被人抛弃
  2. 当新的文件被发现,过程ALL文件从目录日期的升序源目录中运行一个FileSystemWatcher的。 (在你的情况下的FTP文件)
  3. 一旦文件被处理,我将它们移到加工目录(在你的情况下,你可以将它们删除)

需要考虑的事情:

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

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

您提出了一个解决方案,其中队列是文件系统,这是很有可能的,但在许多情况下并不理想。您必须正确锁定,以避免传输半满或空文件等。如果您决定使用文件系统,我的经验是,FileSystemWatcher不能用于此目的。使用计时器来运行任务,每秒钟提取新文件更可靠。其他队列技术可能是内存中队列(但您必须考虑如何处理崩溃),私有Microsoft Message Queue或SQL Server Broker队列。最好的解决方案很大程度上取决于您的要求。

FTP并不是真正的事务性的,你可能会决定使用一个不是事务性的队列(MSMQ和SQL Server Broker都是事务性的),但是你仍然应该围绕事务的概念构建你的应用程序,被创建,排队和交付。如果无法交付,则将其留在队列中,稍后重新投递。如果它不能排队,生产者应该重试排队等等。你不想要一个文件永远不会被传送或被传送两次的情况。

从您的问题中不清楚您将如何使用FTP,但我建议您使用开源或商业库,直接从应用程序中使用FTP,而不是退出到ftp.exe。这将允许您的应用程序在保持FTP连接打开时的智能行为,以避免过度重新连接等。

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

0
  1. 启动一个定时器,每秒触发一次。
  2. 在计时器过去的事件处理程序中,停止计时器。
  3. 获取传入目录中的所有文件的列表。
  4. 尝试专门打开每个文件。这会阻止您读取仍在写入的文件。
  5. 将每个文件复制到暂存目录并从传入目录中删除它。
  6. 移动完列表中的所有文件后,通过FTP发送暂存目录中的文件。
  7. 一旦FTP'd这些文件,从暂存目录中删除它们。
  8. 启动计时器。

计时器的已过时处理程序在线程池中为您运行,并且您应该需要任何更好的线程管理。由于您的主要约束条件是您的FTP带宽,因此在文件上传之前,对其他线程执行其他任何操作都没有多大好处。

这种方法在系统崩溃的情况下为您提供保护。在下一个周期中拾取暂存目录中未发送的文件。传入目录中的文件也一样。

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

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集合

0

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

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