大多数内存有效的方式合并两个文件

时间:2012-12-17 16:13:25

标签: c#

我需要合并两个文件,同时还应用排序。重要的是我将任务点亮在内存使用上。我需要在c#中创建一个控制台应用程序。

输入文件1:

  

某些标题
  A12345334
  A00123445
  A44566555
  B55677
  B55683
  B66489
  记录数:6

输入文件2:

  

某些标题
  A00123465
  B99423445
  记录数:2

所以,我需要确保第三个文件首先包含所有“A”记录,然后是“B”记录,然后是总记录数。

输出文件:

  

一些标题
  A12345334
  A00123445
  A44566555
  A00123465
  B99423445
  B55677
  B55683
  B66489
  记录数:8

“A”和“B”中的记录排序无关。

9 个答案:

答案 0 :(得分:3)

由于您的源文件显示为已排序,因此您可以使用非常低的内存使用量。

只需打开两个输入文件以及一个用于写入的新文件。然后比较每个输入文件中的下一个可用行,并将首先出现的行写入输出文件。每次在输出文件中写入一行时,从它来自的输入文件中获取下一行。

继续,直到两个输入文件都完成。

答案 1 :(得分:0)

如果内存是个问题,最简单的方法可能是从两个文件中读取记录,将它们存储在SQLite或SQL Server Compact数据库中,然后执行返回已排序记录集的SELECT查询。确保在要排序的字段上有索引。

这样,您不必将记录存储在内存中,也不需要任何排序算法;数据库会将记录存储在磁盘上并为您排序。

答案 2 :(得分:0)

我建议您为此应用程序使用StreamReaderStreamWriter。因此,您可以使用StreamWriter打开文件,使用StreamReader复制文件#1的所有行,然后复制文件#2。此操作非常快,具有集成缓冲区并且非常轻量级。

如果输入文件已经按A和B排序,则可以在源阅读器之间切换以对输出进行排序。

答案 3 :(得分:0)

快速想法,假设记录已经在原始文件中排序:

  1. 开始循环浏览文件2,收集所有A记录
  2. 到达第一个B记录后,开始在单独的集合中收集这些记录。
  3. 阅读文件1的全部内容。
  4. 从文件2中写出A-records集合的内容,然后附加从文件1读取的内容,然后附加文件2中的B记录。
  5. 可视化:

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

答案 4 :(得分:0)

如果您担心内存,这是insertion sort的完美案例,并且每个文件一次读取一行。如果这不是一个问题,请将整个内容读入列表,然后调用sort将其写出来。

如果你甚至无法将整个排序列表保存在内存中,那么最好选择数据库或内存映射文件。

答案 5 :(得分:0)

假设您的输入文件已经订购:

  1. 打开输入文件1和2并创建输出文件。
  2. 从文件1中读取第一条记录。如果以A开头,则将其写入输出文件。继续读取输入文件1,直到找到以B开头的记录。
  3. 从文件2中读取第一条记录。如果以A开头,则将其写入输出文件。继续读取输入文件2,直到找到以B开头的记录。
  4. 返回文件1,并将“B”记录写入输出文件。继续读取输入文件1,直到到达流的末尾。
  5. 返回文件2,并将“B”记录写入输出文件。继续读取输入文件2,直到到达流的末尾。
  6. 此方法可以防止您一次只能在内存中保存2行以上的数据。

答案 6 :(得分: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,并相应地对这些行进行流式处理。

答案 7 :(得分: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();
                }
            }
        }
    }
}

答案 8 :(得分: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();
}