0

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

输入文件 1:

一些标头
A12345334
A00123445
A44566555
B55677
B55683
B66489
记录数:6

输入文件 2:

一些 Header
A00123465
B99423445
记录数:2

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

输出文件:

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

“A”和“B”内的记录排序不相关。

4

9 回答 9

3

Since your source files appear sorted, you can do with with very low memory usage.

Just open both input files as well as a new file for writing. Then compare the next available line from each input file and write the line that comes first to your output file. Each time you write a line to the output file, get the next line from the input file it came from.

Continue until both input files are finished.

于 2012-12-17T16:17:18.173 回答
0

If memory is an issue the easiest way to do this is probably going to be to read the records from both files, store them in a SQLite or SQL Server Compact database, and execute a SELECT query that returns a sorted record set. Make sure you have an index on the field you want to sort on.

That way, you don't have to store the records in memory, and you don't need any sorting algorithms; the database will store the records on disk and do your sorting for you.

于 2012-12-17T16:16:31.547 回答
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();
                }
            }
        }
    }
}
于 2012-12-17T17:31:20.633 回答
0

我会推荐使用StreamReaderandStreamWriter用于这个应用程序。因此,您可以使用打开文件StreamWriter,使用文件#1 复制所有行StreamReader,然后使用文件#2 复制所有行。此操作非常快,具有集成缓冲区并且非常轻量级。

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

于 2012-12-17T16:18:41.967 回答
0

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

  1. 开始循环文件 2,收集所有 A 记录
  2. 一旦你到达第一个 B 记录,开始将它们收集到一个单独的集合中。
  3. 阅读所有文件 1。
  4. 从文件 2 中写出 A 记录集合的内容,然后附加从文件 1 读取的内容,然后是文件 2 中的 B 记录。

可视化:

<A-data from file 2>
<A-data, followed by B-data from file 1>
<B-data from file 2>
于 2012-12-17T16:20:43.093 回答
0

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

如果您甚至不能将整个排序列表保存在内存中,那么最好使用数据库或内存映射文件。

于 2012-12-17T16:21:28.080 回答
0

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

  1. 打开输入文件 1 和 2 并创建输出文件。
  2. 从文件 1 中读取第一条记录。如果它以 A 开头,则将其写入输出文件。继续从输入文件 1 读取,直到到达以 B 开头的记录。
  3. 从文件 2 中读取第一条记录。如果它以 A 开头,则将其写入输出文件。继续从输入文件 2 中读取,直到找到以 B 开头的记录。
  4. 返回文件 1,将“B”记录写入输出文件。继续从输入文件 1 读取,直到到达流的末尾。
  5. 返回文件 2,将“B”记录写入输出文件。继续从输入文件 2 读取,直到到达流的末尾。

这种方法将避免您一次在内存中保存超过 2 行的数据。

于 2012-12-17T16:26:07.623 回答
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")))

FileReadLinesWriteAllLineshere 每个都使用IEnumerable并将相应地流式传输这些行。

于 2012-12-17T16:46:24.327 回答
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();
}
于 2016-12-22T07:46:22.343 回答