【问题标题】:C# Merge CSV files with different HeadersC# 合并具有不同标题的 CSV 文件
【发布时间】:2016-03-20 03:15:44
【问题描述】:

我正在尝试合并两个具有不同标题的 csv 文件。当我这样做时,第二个文件添加到 csv 文件的底部而不是它的“右侧”。 例如。 文件 1 的标题为(每列中有数据) A 栏,B 栏,C 栏 文件 2 的标题为(每列中都有数据) F 列,F 列,F 列

在文件 1 中合并后,我希望它读取

col A、b、c、d、e、f

列数据

(每列都有对应的数据)但我的合并是将它添加到文件的底部,所以它看起来像

a、b、c

文件 1 的数据

d、e、f

文件2的数据

当我在 c# 中做我想做的事情时

string file1 = File.ReadAllText(@"C:\file1.csv");
        string file2 = File.ReadAllText(@"C:\file2.csv");
        File.WriteAllText(@"C:\file2.csv", string.Concat(file1, file2));

File.AppendAllText(@"C:\file1.csv", file2);

或使用流式阅读器

StreamWriter wtr = new StreamWriter(@"C:\file1.csv");
wtr.Write(file1 + "\t" + file2); //tried different variations with this one
wtr.Close();
wtr.Dispose();

都给了我同样的结果,没有喜悦。

任何帮助将不胜感激。

【问题讨论】:

  • 我相信你想要Enumerable.Zip
  • 我真的很难想象你如何验证每一行(来自第二个文件)在这个结构的宽度上是匹配的......令人难以置信 :)

标签: c# csv merge


【解决方案1】:

试试下面的

string separator = ","; //Change this to whatever column separator you want.
var file1 = File.ReadLines(@"C:\file1.csv");
var file2 = File.ReadLines(@"C:\file2.csv");
File.WriteAllLines(@"C:\file2.csv", file1.Zip(file2, (f1, f2) => f1 + separator + f2);

首先使用File.ReadLines 将产生一个IEnumerable<string>,它会在您迭代文件时读取文件的每一行。然后,Enumerable.Zip 扩展方法允许您根据每个可枚举中的相对位置连接两个可枚举。最后File.WriteAllLines 将迭代Zip 的结果并将每一行写入您的文件。

另请注意,如果文件的行数不同,Zip 的结果将在到达其中一个文件的末尾时停止。

【讨论】:

  • 请编辑到string[] file1string[] file2。请注意,如果file1 的行数多于file2(或其他方式)Zip 会忽略这些行!
  • @RenéVogt 增加了关于文件长度差异的注释,但是ReadLines的结果是aIEnumerable<string>,而不是string[],但是我只是把它改成了var
  • 好吧,我的错,虽然是string[](但绝对不是string ;))
【解决方案2】:

你必须一行一行地加入他们,而不是一个接一个。框架中没有内置的方法来执行此操作,因此您必须自己编写代码。

您的主要问题是处理文件行数不同的情况。如果保证他们总是有这个,那么操作就比较简单了。下面是一些类似 C# 的伪代码,说明了简单的解决方案:

var first = File.ReadAllLines("firstfile.csv");
var second = File.ReadAllLines("secondfile.csv");
var result = first.Zip(second, (f, s) => string.Join(",", f, s));
File.WriteAllLines("combined.csv", result);

File.ReadAllLines 返回一个字符串数组,每行一个。通过这种方式,您可以轻松读取文件并将文件分成单独的行。

.Zip 是一种 Linq 扩展方法(您必须通过在文件顶部为 System.Linq 添加一个 using 语句来包含它)将两个可枚举项连接在一起,一次一个项目,如拉链。它将每一行传递到您提供的执行连接的函数中——在本例中为(f, s) => string.Join(",", f, s)

string.join 是一种连接由静态文本分隔的字符串的便捷方法。在这种情况下,文本是逗号“,”。它在其他情况下更有用,但我在这里使用它是因为我可以。

File.WriteAllLines 将可枚举字符串的内容写入文件。

现在,如果您必须处理可枚举的长度不同的情况,您必须逐步检查每个集合的每一行并将它们手动连接到输出集合中,为缺失的数据添加空列。这有点复杂,但可以完成。如果您必须处理这种情况,请自行尝试,如果遇到问题,请返回并提出一个新问题,其中包含您的代码中的详细信息。

【讨论】:

  • 太好了,非常感谢,就像一个魅力。谢天谢地,这些文件的行数总是相同的,所以这对我有用。
  • @CM99 请注意,如果您需要对非常大的文件执行此操作,File.ReadAllLines 会将整个文件读入内存,这可能会导致内存不足异常。在这种情况下,您需要改用 File.ReadLines
  • 感谢 Juharr,请记住这一点。非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2017-10-05
  • 1970-01-01
  • 2012-12-08
  • 2019-12-19
  • 1970-01-01
  • 2019-07-18
  • 1970-01-01
  • 2017-09-12
相关资源
最近更新 更多