2012-12-17 39 views
0

我需要在應用排序的同時合併兩個文件。保持內存使用情況的任務很重要。我需要在c#中爲此創建一個控制檯應用程序。合併兩個文件的大多數內存有效方式

輸入文件1:

一些頭
A12345334
A0 A44566555
B55677
B55683
B66489
記錄計數:6

輸入文件2:

一些頭
A0 B99423445
記錄數:2

所以,我需要確保第三檔應首先記錄所有「A」記錄,然後記錄「B」記錄,然後記錄總記錄數。

輸出文件:

一些頭
A12345334
A0 A44566555
A0 B99423445
B55677
B55683
B66489
記錄數: 「A」 和 「B」 內8

記錄排序是不相關的。

+0

遍歷兩個文件,再次提取全部A記錄,然後遍歷並提取B的?那隻會在內存中保留1條記錄,而不得不做4次完整的文件掃描。 –

+2

請向我們展示您嘗試過的方式,並告訴我們您是否遇到特定問題。像這樣的問題通常被視爲「給我一個代碼」,並且對此不以爲然。 – cadrell0

+0

你的檔案大小是? – didierc

回答

0

如果內存是一個問題,最簡單的方法是從兩個文件讀取記錄,將它們存儲在SQLite或SQL Server Compact數據庫中,然後執行一個SELECT查詢,返回一個排序的記錄集。確保你在你想排序的字段上有一個索引。

這樣,您不必將記錄存儲在內存中,也不需要任何排序算法;數據庫會將記錄存儲在磁盤上併爲您排序。

3

由於您的源文件顯示排序,因此可以使用非常低的內存使用量。

只需打開兩個輸入文件以及一個新文件進行書寫。然後比較每個輸入文件的下一行可用行,並將輸出文件的第一行寫入。每次您向輸出文件寫入一行時,都會從它輸入的輸入文件中獲取下一行。

繼續,直到兩個輸入文件完成。

0

我會建議使用StreamReaderStreamWriter這個應用程序。因此,您可以使用StreamWriter打開文件,使用StreamReader對文件#1複製所有行,然後對文件#2複製所有行。這個操作非常快,集成了緩衝區,而且非常輕巧。

如果輸入文件已經按A和B排序,則可以在源讀取器之間切換以使輸出排序。

0

快速的想法,假設記錄已經排序在原始文件:

  1. 開始循環通過的文件2,收集所有A記錄
  2. 一旦你到達第一個B-記錄,開始收集那些在一個單獨的收藏。
  3. 閱讀所有文件1.
  4. 從文件2寫出A-記錄集的內容,然後從文件追加從文件1讀取的內容,其次是B-2的記錄

可視化:

<A-data from file 2> 
<A-data, followed by B-data from file 1> 
<B-data from file 2> 
0

如果您擔心內存這是insertion sort一個完美的情況下,在每個文件一次讀取一行。如果這不是問題,請將整個事情整理成一個列表,然後將其分類寫出來。

如果你甚至無法將整個排序列表保存在內存中,那麼數據庫或內存映射文件是最好的選擇。

0

假設輸入文件已經下令:

  1. 打開輸入文件1和2以及創建輸出文件。
  2. 從文件1中讀取第一條記錄。如果它以A開頭,則將其寫入輸出文件。繼續從輸入文件1中讀取,直到達到以B開頭的記錄。
  3. 從文件2中讀取第一條記錄。如果它以A開頭,則將其寫入輸出文件。繼續從輸入文件2讀取,直到達到以B開頭的記錄。
  4. 返回到文件1,並將'B'記錄寫入輸出文件。繼續從輸入文件1中讀取,直到到達流的末尾。
  5. 回到文件2,並將'B'記錄寫入輸出文件。繼續從輸入文件2中讀取,直到到達流的末尾。

這種方法可以防止你一次只能在內存中保存兩行以上的數據。

0

由於您有兩個排序序列,您只需要將兩個序列合併爲一個序列,就像MergeSort算法的後半部分工作的方式大致相同。

不幸的是,由於IEnumerable提供了接口,它結束了一個有點混亂和複製糊狀,但它應該表現相當好,使用非常小的內存佔用:

public class Wrapper<T> 
{ 
    public T Value { get; set; } 
} 
public static IEnumerable<T> Merge<T>(IEnumerable<T> first, IEnumerable<T> second, IComparer<T> comparer = null) 
{ 
    comparer = comparer ?? Comparer<T>.Default; 

    using (var secondIterator = second.GetEnumerator()) 
    { 
     Wrapper<T> secondItem = null; //when the wrapper is null there are no more items in the second sequence 

     if (secondIterator.MoveNext()) 
      secondItem = new Wrapper<T>() { Value = secondIterator.Current }; 
     foreach (var firstItem in first) 
     { 
      if (secondItem != null) 
      { 
       while (comparer.Compare(firstItem, secondItem.Value) > 0) 
       { 
        yield return secondItem.Value; 
        if (secondIterator.MoveNext()) 
         secondItem.Value = secondIterator.Current; 
        else 
         secondItem = null; 
       } 
      } 
      yield return firstItem; 

      yield return secondItem.Value; 
      while (secondIterator.MoveNext()) 
       yield return secondIterator.Current; 
     } 
    } 
} 

一旦你有一個Merge它的功能是相當簡單:

File.WriteAllLines("output.txt", 
    Merge(File.ReadLines("File1.txt"), File.ReadLines("File2.txt"))) 

文件ReadLinesWriteAllLines這裏的每一個利用IEnumerable,將相應的流線。

0

下面是用於合併排序2個文件的更通用/鍋爐板解決方案的源代碼。

public static void Merge(string inFile1, string inFile2, string outFile) 
{ 
    string line1 = null; 
    string line2 = null; 
    using (StreamReader sr1 = new StreamReader(inFile1)) 
    { 
     using (StreamReader sr2 = new StreamReader(inFile2)) 
     { 
      using (StreamWriter sw = new StreamWriter(outFile)) 
      { 
       line1 = sr1.ReadLine(); 
       line2 = sr2.ReadLine(); 
       while(line1 != null && line2 != null) 
       { 
        // your comparison function here 
        // ex: (line1[0] < line2[0]) 
        if(line1 < line2) 
        { 
         sw.WriteLine(line1); 
         line1 = sr1.ReadLine(); 
        } 
        else 
        { 
         sw.WriteLine(line2); 
         line2 = sr2.ReadLine(); 
        } 
       } 
       while(line1 != null) 
       { 
        sw.WriteLine(line1); 
        line1 = sr1.ReadLine(); 
       } 
       while(line2 != null) 
       { 
        sw.WriteLine(line2); 
        line2 = sr2.ReadLine(); 
       } 
      } 
     } 
    } 
} 
0
public void merge_click(Object sender, EventArgs e) 
{ 
     DataTable dt = new DataTable(); 
     dt.Clear(); 
     dt.Columns.Add("Name"); 
     dt.Columns.Add("designation"); 
     dt.Columns.Add("age"); 
     dt.Columns.Add("year"); 
     string[] lines = File.ReadAllLines(@"C:\Users\user1\Desktop\text1.txt", Encoding.UTF8); 
     string[] lines1 = File.ReadAllLines(@"C:\Users\user2\Desktop\text1.txt", Encoding.UTF8); 
     foreach (string line in lines) 
     { 
      string[] values = line.Split(','); 
      DataRow dr = dt.NewRow(); 
      dr["Name"] = values[0].ToString(); 
      dr["designation"] = values[1].ToString(); 
      dr["age"] = values[2].ToString(); 
      dr["year"] = values[3].ToString(); 
      dt.Rows.Add(dr); 
     } 

     foreach (string line in lines1) 
     { 

      string[] values = line.Split(','); 

      DataRow dr = dt.NewRow(); 
      dr["Name"] = values[0].ToString(); 
      dr["designation"] = values[1].ToString(); 
      dr["age"] = values[2].ToString(); 
      dr["year"] = values[3].ToString(); 
      dt.Rows.Add(dr); 
     } 
     grdstudents.DataSource = dt; 
     grdstudents.DataBind(); 
}