2011-02-11 24 views
1

我想寫一個類,將文件從一個位置複製到另一個並報告進度。我遇到的問題是,當應用程序運行時,進度將立即從0到100%進行拍攝,但該文件仍在後臺進行復制。C#文件流不阻塞,直到寫入/讀取操作完成

public void Copy(string sourceFile, string destinationFile) 
    { 
     _stopWatch.Start(); 

     _sourceStream = new FileStream(srcName, FileMode.Open); 
     _destinationStream = new FileStream(destName, FileMode.CreateNew); 

     read(); 
     //On a 500mb file, execution will reach here in about a second. 
    } 

    private void read() 
    { 
     int i = _sourceStream.Read(_buffer, 0, bufferSize); 

     _completedBytes += i; 

     if (i != 0) 
     { 
      _destinationStream.Write(_buffer, 0, i); 

      TriggerProgressUpdate(); 

      read(); 
     } 
    } 

    private void TriggerProgressUpdate() 
    { 
     if (OnCopyProgress != null) 
     { 
      CopyProgressEventArgs arg = new CopyProgressEventArgs(); 
      arg.CompleteBytes = _completedBytes; 

      if (_totalBytes == 0) 
       _totalBytes = new FileInfo(srcName).Length; 

      arg.TotalBytes = _totalBytes; 

      OnCopyProgress(this, arg); 
     } 
    } 

什麼似乎是發生的是的FileStream只是排隊的操作的操作系統,而不是阻止,直到讀或寫操作完成。

有什麼辦法可以禁用此功能而不會導致巨大的性能損失?

PS。我正在使用測試源和目標變量,這就是爲什麼他們不符合參數。

感謝 克雷格

+1

作爲一個利益的問題,是否有一個原因,你迫使你的應用程序複製一個文件到另一個字節,而不是調用File.Copy()? – 2011-02-11 07:49:10

+0

@bitcrazed:可能會得到一個進度指示器。 – Guffa 2011-02-11 07:53:47

回答

2

調查後發現在FileStream的構造函數中使用「FileOptions.WriteThrough」將禁用寫入緩存。這會導致我的進度正確報告。然而,它會帶來性能的提升,複製需要13秒鐘,而我的應用需要20秒。我將嘗試優化代碼並調整緩衝區大小,以查看是否可以加快速度。

6

我不認爲它可以排隊操作......畢竟,你已經有了一個字節數組,它會有一些數據在Read調用後 - 該數據最好是正確的。這可能只是編寫正在被緩衝的操作。

你可以嘗試在輸出流上定期調用Flush ......我不知道Flush在不同級別的緩存方面會走多遠,但它可能會等到數據實際寫入。編輯:如果你知道這是一個FileStream,你可以撥打Flush(true),這將等待,直到數據實際上被寫入磁盤。

請注意,您不應該經常這樣做,否則性能將受到很大影響。您需要平衡進度精度的粒度與性能代價,以便進行更多控制,而不是讓操作系統優化磁盤訪問。

我很擔心你在這裏使用遞歸 - 在一個非常大的文件中,你可能會因堆棧溢出而無法正常工作。 (CLR有時可以優化尾遞歸方法,但並非總是如此)。我建議你改用循環。這也將更加可讀,國際海事組織:

public void Copy() 
{ 
    int bytesRead; 
    while ((bytesRead = _sourceStream.Read(_buffer, 0, _buffer.Length)) > 0) 
    { 
     _destinationStream.Write(_buffer, 0, bytesRead); 
     _completedBytes += bytesRead; 
     TriggerProgressUpdate(); 
     if (someAppropriateCondition) 
     { 
      _destinationStream.Flush(); 
     } 
    } 
} 

我希望你的處置流的某個地方,順便說一句。我個人儘量避免擁有一次性成員變量。有什麼理由不能在using聲明中使用局部變量?