4

我正在尝试比较 SQL 查询中的两个大型数据集。现在 SQL 查询是在外部完成的,每个数据集的结果都保存到自己的 csv 文件中。我的小 C# 控制台应用程序加载两个文本/csv 文件并比较它们的差异并将差异保存到文本文件中。

它是一个非常简单的应用程序,只需将第一个文件中的所有数据加载到一个数组列表中,并在从第二个 csv 文件中读取每一行时对数组列表执行 .compare() 操作。然后保存不匹配的记录。

该应用程序有效,但我想提高性能。我认为如果我可以利用两个文件都已排序的事实,我可以大大提高性能,但我不知道 C# 中的数据类型可以保持顺序并允许我选择特定位置。有一个基本数组,但我不知道每个列表中有多少项目。我可以拥有超过一百万条记录。是否有我应该查看的可用数据类型?

4

11 回答 11

2

如果两个 CSV 文件中的数据已经排序并且具有相同数量的记录,则可以完全跳过数据结构并进行就地分析。

StreamReader one = new StreamReader("C:\file1.csv");
StreamReader two = new StreamReader("C:\file2.csv");
String lineOne;
String lineTwo;

StreamWriter differences = new StreamWriter("Output.csv");
while (!one.EndOfStream)
{
    lineOne = one.ReadLine();
    lineTwo = two.ReadLine();
    // do your comparison.
    bool areDifferent = true;

    if (areDifferent)
        differences.WriteLine(lineOne + lineTwo);
}

one.Close();
two.Close();
differences.Close();
于 2008-09-16T21:56:47.970 回答
1

System.Collections.Specialized.StringCollection 允许您添加一系列值,并使用 .IndexOf(string) 方法,允许您检索该项目的索引。

话虽如此,您可能只需要从文件流中加载几个 byte[] 并进行字节比较……甚至不必担心将这些内容加载到 StringCollection 或 string[] 等正式数据结构中;如果您所做的只是检查差异,并且您想要速度,我会认为字节差异在哪里。

于 2008-09-16T21:54:19.427 回答
1

这是对 David Sokol 的代码的改编,可以处理不同数量的行,输出一个文件中的行而不是另一个文件中的行:

StreamReader one = new StreamReader("C:\file1.csv");
StreamReader two = new StreamReader("C:\file2.csv");
String lineOne;
String lineTwo;
StreamWriter differences = new StreamWriter("Output.csv");
lineOne = one.ReadLine();
lineTwo = two.ReadLine();
while (!one.EndOfStream || !two.EndOfStream)
{
  if(lineOne == lineTwo)
  {
    // lines match, read next line from each and continue
    lineOne = one.ReadLine();
    lineTwo = two.ReadLine();
    continue;
  }
  if(two.EndOfStream || lineOne < lineTwo)
  {
    differences.WriteLine(lineOne);
    lineOne = one.ReadLine();
  }
  if(one.EndOfStream || lineTwo < lineOne)
  {
    differences.WriteLine(lineTwo);
    lineTwo = two.ReadLine();
  }
}

关于在我脑海中写下的代码的标准警告适用——您可能需要在一个特殊情况下用完行,而另一个仍然有行,但我认为这种基本方法应该可以满足您的需求。

于 2008-09-16T22:28:35.660 回答
0

也许我误解了,但 ArrayList 将按照您添加它们的顺序维护其元素。这意味着您只能在一次通过中比较两个 ArrayList - 只需根据比较结果增加两个扫描索引。

于 2008-09-16T21:52:47.417 回答
0

我的一个问题是您是否考虑过“外包”您的比较。有很多好的差异工具,你可以直接调用。如果没有一个可以让您指定两个文件并仅获取差异,我会感到惊讶。只是一个想法。

于 2008-09-16T21:53:22.750 回答
0

我认为每个人都有这么多不同答案的原因是你没有很好地确定你的问题足以得到回答。首先,这取决于您要跟踪什么样的差异。您是否希望像在 WinDiff 中一样输出差异,其中第一个文件是“原始”文件,第二个文件是“修改过的”文件,以便您可以将更改列为 INSERT、UPDATE 或 DELETE?您是否有一个主键,可以让您将两行匹配为同一记录的不同版本(当主键以外的字段不同时)?或者这是某种和解,您只希望您的差异输出说“在文件 1 中而不是文件 2 中记录”之类的内容?

我认为这些问题的答案将帮助每个人为您的问题提供合适的答案。

于 2008-09-16T22:13:31.097 回答
0

如果您有两个文件,如您的帖子中所述,每个文件都是一百万行,那么您可能会占用大量内存。一些性能问题可能是您正在从磁盘交换。如果您只是将文件 A 的第 1 行与文件 B 的第 1 行、第 2 行文件 A -> 第 2 行文件 B 等进行比较,我会推荐一种不会在内存中存储太多的技术。您可以读取先前评论者发布的两个文件流的注销,并在找到结果时“实时”写出结果。这不会在内存中显式存储任何内容。您还可以将每个文件的块转储到内存中,比如一次一千行,转储到类似列表的东西中。这可以进行微调以满足您的需求。

于 2008-09-16T22:23:30.183 回答
0

要解决问题 #1,我建议考虑创建每行的哈希。这样您就可以使用字典快速轻松地比较哈希值。

要解决问题 #2,一个快速而肮脏的解决方案是使用 IDictionary。使用 itemId 作为您的第一个字符串类型,并将该行的其余部分作为您的第二个字符串类型。然后,您可以快速查找 itemId 是否存在并比较行。这当然假设.Net 2.0+

于 2008-09-18T14:05:53.090 回答
0

好吧,有几种方法可行。您可以编写自己的数据结构来执行此操作。或者您可以尝试使用 SortedList。您还可以在代码中返回 DataSet,然后在表上使用 .Select()。当然,您必须在两张桌子上都这样做。

于 2008-09-16T21:50:39.263 回答
0

您可以轻松地使用 SortedList 进行快速查找。如果您正在加载的数据已经排序,则插入到 SortedList 中的速度应该不会很慢。

于 2008-09-16T21:50:50.277 回答
0

如果您只是想查看 FileA 中的所有行是否都包含在 FileB 中,则可以将其读入并比较循环内的流。

文件 1 条目 1 条目 2 条目 3

文件 2 条目 1 条目 3

您可以使用两个计数器循环并查找遗漏,逐行浏览每个文件,看看是否得到了所需的内容。

于 2008-09-16T21:52:24.110 回答