如何在c#中从csv中提取头文件

时间:2018-05-31 10:27:58

标签: c# .net csv

我将csv文件加载并拆分为c#中的两个列表。现在我还需要从第一行中提取标题;为delmiter。我尝试使用.Skip(1)命令,但只跳过(显然),但我需要提取标题,在我完成其余数据工作后,再次添加它作为第一行。

这是我到目前为止所尝试的内容:

string[] fileNames = Directory.GetFiles(@"read\", "*.csv");
for (int i = 0; i < fileNames.Length; i++)
{
    string file = @"read\" + Path.GetFileName(fileNames[i]);
    var lines = File.ReadLines(file).Skip(1);
    (List<string> dataA, List<string> dataB) = SplitAllTodataAAnddataB(lines);
    var rowLog = 0;
    foreach (var line in dataA)
    {
       // Variablen für lines
       string[] entries = line.Split(';');
       rowLog++;
       Helper.checkdataAString(entries[0].ToLower(), "abc", rowLog);
       Helper.checkdataAString(entries[1].ToLower(), "firstname", rowLog);
       Helper.checkdataAString(entries[2].ToLower(), "lastname", rowLog);
       Helper.checkdataAString(entries[4].ToLower(), "gender", rowLog);
       Helper.checkdataAString(entries[5].ToLower(), "id", rowLog);
       Helper.checkdataAString(entries[3], "date", rowLog);
       Helper.drawTextProgressBar("loaded rown", rowLog, dataA.Count());
    }
    Console.WriteLine("\nencryypting data");
    var output = new List<string>();
    foreach (var line in dataA)
    {
       try
       {
          string[] entries = line.Split(';');
          string abc = entries[0].ToLower();
          string firstName = koeln.GetPhonetics(entries[1]).ToLower();
          string lastName = koeln.GetPhonetics(entries[2]).ToLower();
          string date = entries[3];
          //Hier werden die drei vorherigen Variablen konkatiniert.
          string NVG = FirstName + "_" + LastName + "_" + BirthDate;
          string gender = entries[4].ToLower();
          string age = Helper.Left(Convert.ToString(20171027 - Convert.ToInt32(entries[3])), 2);
          string zid = Guid.NewGuid().ToString();
          string fid = entries[5].ToLower();
          rowdataA++;
          output.Add($"{abc}; {NVG}; {gender}; {age}; {zid}; {fid}");
          Helper.drawTextProgressBar("encrypted rows.", rowdataA, dataA.Count());
       }
       catch { rowdataA++; }
    }
    File.WriteAllLines(fileTest, output);
}

我有点新的发展,所以我只是尝试,任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:2)

你可以这样读取文件:

string file = @"read\" + Path.GetFileName(fileNames[i]);
var content = File.ReadLines(file);

var header = content.ElementAt(0);
var lines = content.Skip(1);

答案 1 :(得分:1)

答案

List<string> lines = File.ReadLines(file);

这包含文件中的所有行。我们知道第一行是标题,其余的是内容。

List<string> contentLines = lines.Skip(1);

这是您在代码中所拥有的。它包含之外的所有行<。

那么我们如何才得到标题行?

string headerLine = lines.First();

我们走了。请注意,这会返回单个字符串,而不是字符串列表 如果你想收到一个字符串列表(例如,如果你有一个跨越两行或更多行的标题),那么你可以这样做:

List<string> headerLines  = lines.Take(amount_of_header_lines);
List<string> contentLines = lines.Skip(amount_of_header_lines);

简单地说,Take(X)获取前X个项目,而Skip(X)除了前X个项目。

脚注

  • 请注意,我先将lines = File.ReadLines(file)放在一个单独的变量中。如果我为标题行和内容行调用了File.ReadLines(file)(而不是使用lines变量),我会读两次文件。这对你来说可能并不重要,但它可能导致性能问题,而且这是毫无意义的工作。
  • 将标题行拆分为部分的逻辑与将内容行拆分为部分的逻辑相同。
  • 我使用了Single。您可能希望使用SingleOrDefault(或者您可能不会)。但这与不同的讨论有关,而不是这里的重点。
  • 您的代码考虑了简单的CSV结构,但这可能会非常复杂。
    • 如果要使用分号作为单元格值的一部分,则将单元格值包装在引号中。例如,请注意,此数据仅代表三个列:ColumnA;"ColumnB;StillColumnB";ColumnC。您的代码(line.Split(';'))不会考虑到这一点。
    • 表格的一行(在Excel中)可以分为两行(当您在文本编辑器中查看csv文件时)。如果单元格值中存在换行符,则会发生这种情况。 File.ReadLines()没有考虑到这一点。
    • 尝试为看似简单数据格式创建解析器时;始终检查是否存在现有库。 不要重新发明轮子(除非是出于培训目的)。您目前没有考虑过很多边缘情况,但最终会成为您最初简单代码的死亡。
  • 不打算任何冒犯,你的代码不是最干净的。如果您对提高质量感兴趣,我建议将此代码发布到CodeReview StackExchange(请注意您是初学者,因此您不会对复杂的解释感到不知所措)。 CodeReview仅允许使用代码,因此您需要在发布之前完成它。

答案 2 :(得分:1)

如果我理解正确,你需要读取整个文件,处理除标题之外的所有行,然后用标题和处理过的行写回不同的文件,对吗?

如果是这样,以下方法应该有效:

var allLines = File.ReadAllLines(originalFile);
var headerLine = allLines.First();
var dataLines = allLines.Skip(1);
var processedLines = ProcessLines(dataLines);
File.WriteAllLines(newFile, (new[] {headerLine}.Concat(processedLines)).ToArray());

ProcessLines方法会接受原始行作为参数,并返回包含已处理行的列表:

IEnumerable<string> ProcessLines(IEnumerable<string> originalLines)
{
    var processedLines = new List<string>();
    foreach(var line in originalLines)
    {
        var processedLine = //generate your processed line here
        processedLines.Add(processedLine);
    }
    return processedLines;
}