【问题标题】:Parsing Tab delimited text files解析制表符分隔的文本文件
【发布时间】:2014-04-22 17:07:29
【问题描述】:

我有一个 制表符分隔 文件,其中包含一些列和行,例如:某些行可能对某些列没有价值。 我们所知道的是“顺序”不会改变,所以第三个制表符分隔的东西总是用于 Column3 等等。

Column1  Column2  Column3 .... Column12 .... Column34 ... Column50
123  34 ABC
234     DEF                                   as@ddd.com    True
     45           NYC                         wwe@dsds.com  False      

现在我需要阅读此文件,但并非所有列对我的程序都很重要。例如,我只需要对 Column2、Column12、Column45 中的值做一些事情

你有什么建议?

【问题讨论】:

  • 逐行阅读,在标签上拆分,获取您需要的列。您还在寻找什么?
  • 您是在寻求意见,还是在问题的特定部分遇到问题?
  • @Jonesy 我不知道这部分:“抓住你需要的列” 另外,如果文件很大,读取文件不会崩溃或内存不足的有效方法是什么?

标签: c#


【解决方案1】:

尝试以下方法

static void Main(string[] args)
{
    DataTable datatable = new DataTable();
    StreamReader streamreader = new StreamReader(@"C:\Temp\txt.txt");
    char[] delimiter = new char[] { '\t' };
    string[] columnheaders = streamreader.ReadLine().Split(delimiter);
    foreach (string columnheader in columnheaders)
    {
        datatable.Columns.Add(columnheader); // I've added the column headers here.
    }

    while (streamreader.Peek() > 0)
    {
        DataRow datarow = datatable.NewRow();
        datarow.ItemArray = streamreader.ReadLine().Split(delimiter);
        datatable.Rows.Add(datarow);
    }

    foreach (DataRow row in datatable.Rows)
    {
        Console.WriteLine(""----Row No: " + datatable.Rows.IndexOf(row) + "----"");

        foreach (DataColumn column in datatable.Columns)
        {
            //check what columns you need
            if (column.ColumnName == "Column2" || 
                column.ColumnName == "Column12" ||
                column.ColumnName == "Column45") 
            {
                Console.Write(column.ColumnName);
                Console.Write(" ");
                Console.WriteLine(row[column]);
            }
        }
    }
    Console.ReadLine();
}

【讨论】:

  • 哇..美丽 :) 您有什么最终想法和考虑吗?还是你觉得不错,我就去用它?
  • 我很好奇你为什么选择这个答案而不是@Sudhakar's?在我看来,这要简单得多
  • @Jonesy 正确,我仍在评估它们。现在不知道为什么这个答案没有保持它打印的记录的顺序与输入文件中的相同....
  • @Jonesy 也试过了,它崩溃了。
  • @DevWannaBe - 我不知道您所说的未维护的记录顺序是什么意思。我更新了代码以显示输入文件中的行索引。我希望这可以帮助您了解输入文件中每一行的顺序。
【解决方案2】:

不要自己动手。有……微妙之处不是立即显现出来的。其中:

  • 引用的字段?
  • 包含嵌入字段和/或记录分隔符的数据
  • 长度错误的记录

改为使用像 Sebastien Lorion 最优秀的 Fast CSV Reader 之类的东西,来自 CodeProject

编辑说明:尽管名称如此,但它是用于分隔文本文件的通用阅读器。可配置的项目包括

  • 字段分隔符
  • 记录分隔符
  • 引号字符(用于引用文本)
  • 转义字符(用于嵌入引号)
  • 允许或不允许评论的地方。如果启用,注释字符(见下文)开始注释,以下一个记录分隔符结束。
  • 评论字符(默认为'#')
  • 第一行是否为标题,包含字段名称。

【讨论】:

  • 谢谢,但我的是制表符分隔的文本文件。您建议的是 CSV 吗?
  • 唯一的区别是您选择的字段和记录分隔符。只需将其配置为使用 HT ('\t') 而不是逗号 (',') 作为字段分隔符。
【解决方案3】:
var list = from row in System.IO.File.ReadLines("file.txt")
           let arr = row.Split('\t')
           select new Tuple<string, string, string>(arr[2], arr[12], arr[45]);

【讨论】:

  • 这应该是公认的答案。非常简单,并且在获取数据后易于操作。如果您希望拥有适当的数据模型,我也喜欢@Sudhakar Tillapudi 的回答。逐行阅读似乎令人生畏,只需给我所有数据。这里的问题是,如果您想读取包含许多列的文件的每一列
【解决方案4】:

您可以使用File.ReadLines() 方法(如果您使用的是 .NET Framework 4.0 或更高版本)而不会降低性能,因为它不会将整个文件内容加载到内存中。

试试这个:

using System.IO;

class FileData
{
public string Column2{ get; set; }
public string Column12{ get; set; }
public string Column45{ get; set; }
}


List<FileData> filedata =  new List<FileData>();

 FileData temp = new FileData();
 foreach(var line in File.ReadLines("filepath.txt").Skip(1))
 {     
   var tempLine = line.Split('\t');
   temp.Column2 = tempLine[1];
   temp.Column12 = tempLine[11];
   temp.Column45 = tempLine[44]; 
   filedata.Add(temp);
 }

【讨论】:

  • 一个已定义对象结构的列表可能比三个独立的值列表更好:)
  • 如何忽略文件的第一行?这是列名..下一行是数据,但第一行是列名 Column1 Column2 Column3 .... Column12 .... Column34 ... Column50
  • @DevWannaBe:将foreach 转换为for 并跳过第一行,或者引入计数器或标志变量。像var skip = true 这样的东西,然后在循环中if (skip) { skip = false; continue; }。无论哪种方式都可行,这只是您认为更具可读性/可支持性的问题。
  • 为什么不只是File.ReadLines("filepath.txt").Skip(1))
  • @Jonesy:好点,编辑了我的帖子
【解决方案5】:

只需读取文件的所有行,然后按制表符分隔,即可访问每一列。

   var fileArray = File.ReadAllLines(myLocation);
    
        for(int i=0;i<fileArray.Length;i++)
        {
           var line=fileArray[i];

           if (i == 0)
           {  
              //handle column names
           }
           else
           {
             var columns = line.Split('\t');
             string value = columns[3];
           }
        }

【讨论】:

  • 文件可能很大,有没有更高效的方法可以一次读取一行?
  • 修改后的答案也可以处理列名
  • in for(int i=0;i
  • 抱歉,我之前的回答打错了
  • 不完整的例子 - 你需要定义什么是行。
【解决方案6】:

正如 Nicholas 所说,不要自己动手,因为有细微之处和特殊情况。

一个选项是TextFieldParser

using (var parser = new TextFieldParser(filePath))
{
    parser.TextFieldType = FieldType.Delimited;
    parser.SetDelimiters("\t");

    while (!parser.EndOfData)
    {
        var cols = parser.ReadFields();
        // Can now access columns, eg cols[0]
    }
}

【讨论】:

  • 这需要 .net5.0。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-16
  • 2015-02-14
  • 2017-07-17
相关资源
最近更新 更多