2009-05-19 74 views

回答

8

新的答案

(請參閱下面的廢棄,另外添購原有答案的解釋。)

static void CopyFiles(string dest, params string[] sources) 
{ 
    using (TextWriter writer = File.CreateText(dest)) 
    { 
     // Somewhat arbitrary limit, but it won't go on the large object heap 
     char[] buffer = new char[16 * 1024]; 
     foreach (string source in sources) 
     { 
      using (TextReader reader = File.OpenText(source)) 
      { 
       int charsRead; 
       while ((charsRead = reader.Read(buffer, 0, buffer.Length)) > 0) 
       { 
        writer.Write(buffer, 0, charsRead); 
       } 
      } 
     } 
    } 
} 

這個新的答案非常喜歡馬丁的做法,除了:

  • 它讀成較小的緩衝區16K將是在幾乎所有情況下接受的,而且在大對象堆不會結束(不得到壓實)
  • 它讀取文本數據,而不是二進制數據,原因有二:
    • 的代碼可以容易地被修改以從一種編碼轉換爲另一種
    • 如果每個輸入文件包含一個字節順序標記,將由讀取器被跳過,而不是用散射字節順序標記結束了通過輸入文件的輸入文件邊界

原來的答覆

馬丁別人接受指出了下面的答案的一個問題 - 如果第一個文件,而無需換行結束,它仍然會造成在輸出文件中換行。此外,即使它們以前只是「\ r」或「\ n」,它也會將換行符轉換爲「\ r \ n」。最後,它毫無意義地冒着爲長線使用大量數據的風險。

喜歡的東西:

static void CopyFiles(string dest, params string[] sources) 
{ 
    using (TextWriter writer = File.CreateText(dest)) 
    { 
     foreach (string source in sources) 
     { 
      using (TextReader reader = File.OpenText(source)) 
      { 
       string line; 
       while ((line = reader.ReadLine()) != null) 
       { 
        writer.WriteLine(line); 
       } 
      } 
     } 
    } 
} 

注意,這逐行地讀取,以避免過分解讀內存在的時間。如果你(在時間還是一個)很高興能完整地閱讀每一個文件到內存中,你可以更簡單:

static void CopyFiles(string dest, params string[] sources) 
{ 
    using (TextWriter writer = File.CreateText(dest)) 
    { 
     foreach (string source in sources) 
     { 
      string text = File.ReadAllText(source); 
      writer.Write(text); 
     } 
    } 
} 
+0

Skeet再次擊敗我! – jrcs3 2009-05-19 20:44:17

+0

他只是看看他的鍵盤,它開始用光速輸入答案。:) – 2009-05-19 20:45:22

2

編輯

由於喬恩斯基特指出,文本文件通常應被處理的方式不同於二進制文件 。

我剛剛離開這個答案,因爲它可能是更好的性能,如果你有非常大的文件,而不是通過編碼的問題(例如,具有在輸出文件中不同的編碼或多個Byte Order Marks不同的輸入文件)concernded:

public void CopyFiles(string destPath, string[] sourcePaths) { 
    byte[] buffer = new byte[10 * 1024 * 1024]; // Just allocate a buffer as big as you can afford 
    using (var destStream= = new FileStream(destPath, FileMode.Create) { 
    foreach (var sourcePath in sourcePaths) { 
     int read; 
     using (var sourceStream = FileStream.Create(sourcePath, FileMode.Open) { 
     while ((read = sourceStream.Read(buffer, 0, 10*1024*1024)) != 0) 
      destStream.Write(buffer, 0, read); 
     } 
    } 
    } 
} 
相關問題