2012-06-14 53 views
4

我有以下情况,我必须复制多个(大约10,50,200,...)文件。我一个接一个地同步。这是我的代码片段。在线程中复制多个文件

static void Main(string[] args) 
     { 
      string path = @""; 
      FileSystemWatcher listener = new FileSystemWatcher(path); 
      listener.Created += new FileSystemEventHandler(listener_Created); 
      listener.EnableRaisingEvents = true; 

      while (Console.ReadLine() != "exit") ; 
     } 

     public static void listener_Created(object sender, FileSystemEventArgs e) 
     { 
      while (!IsFileReady(e.FullPath)) ; 
      File.Copy(e.FullPath, @"D:\levani\FolderListenerTest\CopiedFilesFolder\" + e.Name); 
     } 

所以当某个文件夹中创建的文件,它已经准备好使用我复制该文件一个又一个,但我要开始任何文件就可以使用了,一旦复制。所以我认为我应该使用线程。所以.. 如何实现并行复制?

@克里斯

检查文件是否已准备

public static bool IsFileReady(String sFilename) 
     { 
      // If the file can be opened for exclusive access it means that the file 
      // is no longer locked by another process. 
      try 
      { 
       using (FileStream inputStream = File.Open(sFilename, FileMode.Open, FileAccess.Read, FileShare.None)) 
       { 
        if (inputStream.Length > 0) 
        { 
         return true; 
        } 
        else 
        { 
         return false; 
        } 

       } 
      } 
      catch (Exception) 
      { 
       return false; 
      } 
     } 
+0

也是一个警告的话......我相信创建的事件会在文件第一次创建时触发。如果文件需要一些时间来创建,你可能会发现你正在试图在它写完之前处理它... – Chris

+1

@Chris在这里while(!IsFileReady(e.FullPath)); – levi

+0

D'oh! :)你是如何检查出来的兴趣?我从来没有发现任何特别好的方法来检查它... – Chris

回答

11

从机械硬盘做并行I/O是一个坏主意,只会放慢改革的步伐,为机械头部需求每次都要旋转以寻找下一个读取位置(一个非常缓慢的过程),然后在每个线程轮到它运行时被反弹。

坚持顺序方法并在单个线程中读取文件。

1

现在只有(@Tudor说的),但并行复制文件会由于碎片而将硬盘驱动器混乱。在我的应用程序中,我使用排队的200个同时复制以前生成的文件,只是以'线性'方式将它们放在硬盘上。

您可以阅读更多的主题here

1

你可能有一个Thread它做所有的处理即

Queue files = new Queue(); 

static void Main(string[] args) 
{ 
     string path = @""; 
     FileSystemWatcher listener = new FileSystemWatcher(path); 
     Thread t = new Thread(new ThreadStart(ProcessFiles)); 
     t.Start(); 
     listener.Created += new FileSystemEventHandler(listener_Created); 
     listener.EnableRaisingEvents = true; 

     while (Console.ReadLine() != "exit") ; 
} 


public static void listener_Created(object sender, FileSystemEventArgs e) 
{ 
    files.Enqueue(e.FullPath); 
} 

void ProcessFiles() 
{ 
    while(true) 
    { 
     if(files.Count > 0) 
     { 
       String file = files.Dequeue(); 
       while (!IsFileReady(file)) ; 

       File.Copy(file, @"D:\levani\FolderListenerTest\CopiedFilesFolder\" +   file); 
     } 
    } 
} 

而在你的listener事件中添加文件名的队列。

然后在您的Thread中,您可以从队列中抓取文件名并从那里进行处理。

+0

仍然会是单线程同步工作,不是吗? – levi

+0

是的,因为所有的处理都在一个'Thread'上。但是,在'Thread'开始之后,您仍然可以执行处理,让您在'Main'中进行其他处理。 –

+0

谢谢你的方法,看起来很帅 – levi