【问题标题】:How to read from a text file which does not have consisted data?如何从不包含数据的文本文件中读取?
【发布时间】:2020-12-10 23:32:11
【问题描述】:

我有一个文本文件,其中存储有关生产信息和流程的信息。该过程由几个阶段组成,例如StrippingCleaningPaint 等。这些阶段存储的日期可能是expected datestart datefinished datedelay date

.txt 文件示例:

567,埃因霍温,21,Stripping_e=20/05/2020,Stripping_s=21/05/2020,Stripping_f=22/05/2020,Cleaning_e=23/05/2020,Cleaning_s=27/05/2020,Cleaning_f =28/05/2020,Paint_e=28/05/2020,Panint_s=28/05/2020,Paint_f=29/05/2020,Cabinet_e=29/05/2020,Cabinet_s=31/05/2020,Cabinet_f=, Table_e=,Table_s=,Table_f=,Stand_e=,Stand_s=,Stand_f=,Display_e=,Display_s=,Display_f=,UControls_e=,UControls_s=,UControls_f=,Test_e=,Test_s=,Test_f=,Prepack_e=,Prepack_s= ,Prepack_f=,Endpack_e=,Endpack_s=,Endpack_f=,Release_e=,Release_s=,Release_f=,

读完这个 .txt 文件后,我将它存储在 dataGridView 中,例如:

但是,我不知道如何将最新日期添加到相应的列中。如果我在文本文件中看到Stripping_f,我想覆盖Stripping 列中的Stripping_e 值。其余列也是如此。这也是我不一定有专栏的日期(预期、开始、完成或延迟)的原因。

这是我目前使用的代码:

private void IGT_Load(object sender, EventArgs e)
        {
            table.Columns.Add("SalesNr", typeof(int));
            table.Columns.Add("PName", typeof(string));
            table.Columns.Add("Type", typeof(int));
            table.Columns.Add("Stripping", typeof(string));
            table.Columns.Add("Cleaning", typeof(string));
            table.Columns.Add("Paint", typeof(string));
            table.Columns.Add("Cabinet", typeof(string));
            table.Columns.Add("Table", typeof(string));
            table.Columns.Add("Stand", typeof(string));
            table.Columns.Add("Display", typeof(string));
            table.Columns.Add("User Controls", typeof(string));
            table.Columns.Add("Test", typeof(string));
            table.Columns.Add("Pre-pack", typeof(string));
            table.Columns.Add("End-pack", typeof(string));
            table.Columns.Add("Release for Delivery", typeof(string));
            dataGridView1.DataSource = table;
            Import();
        }

        private void Import()
        {
            // get lines from the text file
            string[] lines = File.ReadAllLines(@"..\..\567.txt");
            string[] values;


            for (int i = 0; i < lines.Length; i++)
            {
                values = lines[i].ToString().Split(',', '=');
                string[] row = new string[values.Length];

                for (int j = 0; j < values.Length; j++)
                {
                    
                    if(values[j] == "Stripping_e")
                    {
                        row[j] = values[j + 1].Trim();
                        j++;
                    }
                    else if (values[j] == "Stripping_s")
                    {
                        row[j-2] = values[j+1].Trim();
                        j++;
                    }
                    else if(values[j] == "Cleaning_s" || values[j] == "Cleaning_e" || values[j] == "Cleaning_f" || values[j] == "Cleaning_d")
                    {
                        row[j] = values[j + 1].Trim();
                    }
                    else
                    {
                        row[j] = values[j].Trim();
                    }
                }
                table.Rows.Add(row);
            }
        }

table 是一个DataTable 连接到dataGridView1 作为DataSource

我以前从未使用过文本文件,因此非常感谢您的帮助!

【问题讨论】:

  • @sumit_programmer 我看到你回答了一个类似的问题,你能帮我解决这个问题吗?
  • 您当前的代码有什么问题?你能更具体地描述一下吗?
  • @dymanoid 在我当前的代码中,我假设我已经预期、开始、完成和延迟。例如,根据这个假设,我使用j-2 进行剥离。但是,如果我没有stripping_s 值,那么我的cleaning_e 将永远无法正确找到,因为会执行j-3 之类的操作...
  • 我需要查看更多的文本文件。看起来您有重复的文件部分,需要查看几个部分才能正确编写代码。
  • @jdweng 我编辑了这个例子。阶段不一定必须包含日期(这是因为我们在工厂还不知道日期),也可能会有延迟,例如Cabinet_d=

标签: c# datagridview text-files


【解决方案1】:

读取半非结构化 CSV 可能会很棘手,您必须坚信 CSV 文件始终正确。例如,如果某个类别的某个日期拼写错误,例如……“Panint_s=28/05/2020”……在发布的数据中……那么,在下面的代码中,这种拼写错误不会引发任何类型的错误或消息,它永远不会被使用。所以,编码器要小心。下面是一种这样的“hacky”方法。

您可能遇到的一个复杂情况是当前代码如何使用字符串数组 (string[])。这将使事情变得更加复杂。当代码到达SomeCategory=SomeDate 时,它很有用。下面,一个字符串数组用于这些拆分以获取类别的日期。在代码的其他地方,它使用List&lt;string&gt; 来分隔数据中的行。当我们想要获取“特定”类别的日期时,这将有所帮助。更多内容如下。

因此,给定一个string 的数据,如您所显示的,这样string 是网格中的“单”行,那么我将用逗号“拆分”该字符串“,”。然后将字符串数组转换为List&lt;string&gt;。它可能看起来像……

List<string> SplitRow = curRow.Split(',').ToList();

鉴于发布的单行数据,List&lt;string&gt;allData 可能看起来像……。

可以看出,我们将使用这个List&lt;string&gt; 来获取网格中前三个单元格的数据,并且当我们到达想要获取特定类别“最新”日期的代码部分时,我们可以“过滤”这个List&lt;string&gt;,只包含我们想要的类别。如果allData 是上面的List&lt;string&gt;,那么要过滤列表以仅包含我们想要的类别,代码可能看起来像……

String targetCategory = “Stripping”;
List<string> categoryData = allData.Where(x => x.Contains(targetCategory)).ToList();

这将产生一个List&lt;string&gt;categoryData,其中只有“剥离”类别。如下图……

通过这个列表,我们可以遍历所有字符串,解析日期并返回所有给定日期的最新日期。如果我们创建一个返回此日期字符串的方法,那么我们可以使用它为每一行分配网格中的每个类别列。

因此,采用allData 列表和string 类别进行过滤的方法可能会派上用场。此方法可能如下所示……

private string GetLatestDateForCategory(List<string> allData, string targetCategory) {
  List<string> categoryData = allData.Where(x => x.Contains(targetCategory)).ToList();
  DateTime latestDate = DateTime.MinValue;
  string[] splitArray;
  foreach (string catLine in categoryData) {
    splitArray = catLine.Split('=');
    if (splitArray.Length >= 2) {
      if (DateTime.TryParseExact(splitArray[1], "dd/MM/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date)) {
        if (date > latestDate) {
          latestDate = date;
        }
      } 
    }
  }
  if (latestDate != DateTime.MinValue) {
    return latestDate.ToShortDateString();
  }
  return "";
}

遍历此方法将从“过滤”所有数据以获取targetCategory 字符串值的列表开始。然后创建一个DateTime 变量来比较日期并用作最新日期。我们将日期设置为“min”值,我们将使用这个“min”日期来指示该类别在数据中没有日期。接下来是字符串数组splitArray,用于在“=”字符上分割每个字符串。

开始循环遍历列表中的所有过滤字符串。在“=”字符上拆分字符串后,会进行检查以确保字符串中有日期。如果有日期字符串,则将该日期解析为DateTime 对象以便于比较。如果日期解析成功,则代码会将解析日期检查为最新日期。如果解析的日期晚于当前的latestDate,则更新它以反映这个较新的最新日期。

检查完所有日期后,代码将检查latestDate。如果latestDate 仍然是“Min”值,则意味着没有找到该类别的日期并返回一个空字符串,否则代码将返回最新的日期字符串。

如果代码循环遍历数据中存在大量行的每个字符串,那么当我们想从特定类别中获取最新日期时,上面的方法将派上用场。

因此,将它们放在一起可能如下所示……

private void Import() {
  List<string> allLines = File.ReadAllLines(@"D:\Test\CSV\567.txt").ToList();
  DataRow dr;
  List<string> SplitRow;
  int value;
  foreach (string curRow in allLines) {
    dr = table.NewRow();
    SplitRow = curRow.Split(',').ToList();
    if (SplitRow.Count >= 3) {
      value = 0;
      if (int.TryParse(SplitRow[0], out value)) {
        dr["SalesNr"] = value;
      }
      if (int.TryParse(SplitRow[2], out value)) {
        dr["Type"] = value;
      }
      dr["PName"] = SplitRow[1];
      dr["Stripping"] = GetLatestDateForCategory(SplitRow, "Stripping");
      dr["Cleaning"] = GetLatestDateForCategory(SplitRow, "Cleaning");
      dr["Paint"] = GetLatestDateForCategory(SplitRow, "Paint");
      dr["Cabinet"] = GetLatestDateForCategory(SplitRow, "Cabinet");
      dr["Table"] = GetLatestDateForCategory(SplitRow, "Table");
      dr["Stand"] = GetLatestDateForCategory(SplitRow, "Stand");
      dr["Display"] = GetLatestDateForCategory(SplitRow, "Display");
      dr["User Controls"] = GetLatestDateForCategory(SplitRow, "UControls");
      table.Rows.Add(dr);
    }
  }
}

首先要从 CSV 文件中获取 List&lt;string&gt; 来了解此方法。在发布的数据中,这将是列表中的单个字符串。接下来定义DataRowdr,我们将使用这一行来添加我们从数据中获得的值。另一个List&lt;string&gt; SplitRow 用于列表中的“每个”字符串。最后,一个int value 用于解析intSalesNrType

开始循环遍历所有数据中的每个字符串,从现有的table 创建一个新的DataRow,然后用逗号“;”分割当前字符串。进行检查以确保 SalesNr、PName 和 Type 至少有三 (3) 个值。解析 SalesNrType 值,然后将 PName 字符串值设置到新行中。然后,每个“类别”将使用上述方法为每个类别设置日期字符串。最后,将该行添加到table。注意:并非所有类别都填写在代码中。

我希望这是有道理的。它很老套,但在我的测试中有效。祝你好运。

【讨论】:

    【解决方案2】:

    这就是我会做的方式。

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;
    using System.Globalization;
    
    namespace WindowsFormsApplication71
    {
        public partial class Form1 : Form
        {
            const string FILENAME = @"c:\temp\test.csv";
            public Form1()
            {
                InitializeComponent();
    
                StreamReader reader = new StreamReader(FILENAME);
                string line = "";
                int row = 0;
                DataTable dt = new DataTable();
                while ((line = reader.ReadLine()) != null)
                {
                    line = line.Trim();
                    if (line.Length > 0)
                    {
                        string[] columns = line.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray();
                        List<object> newRow = new List<object>(); ;
                        if (++row == 1)
                        {
                            dt.Columns.Add("SalesNr", typeof(string));
                            dt.Columns.Add("PName", typeof(string));
                            dt.Columns.Add("Type", typeof(int));
                        }
                        for (int col = 0; col < columns.Length; col++)
                        {
                            switch (col)
                            {
                                case 0:
                                    newRow.Add(columns[0]);
                                    break;
                                case 1:
                                    newRow.Add(columns[1]);
                                    break;
                                case 2:
                                    newRow.Add(columns[2]);
                                    break;
                                default:
                                    string[] keyValue = columns[col].Split(new char[] { '=' });
                                    if (row == 1)
                                    {
                                        dt.Columns.Add(keyValue[0], typeof(DateTime));
                                    }
                                    if (keyValue[1].Trim().Length > 0)
                                    {
                                        newRow.Add(DateTime.ParseExact(keyValue[1], "dd/MM/yyyy", CultureInfo.InvariantCulture));
                                    }
                                    else
                                    {
                                        newRow.Add(null);
                                    }
                                    break;
                            }
                        }
                        dt.Rows.Add(newRow.ToArray());
                    }
                }
                dataGridView1.DataSource = dt;
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-12-23
      • 1970-01-01
      • 1970-01-01
      • 2016-10-05
      • 1970-01-01
      • 2015-01-21
      • 2011-10-30
      • 2012-06-10
      • 2021-10-22
      相关资源
      最近更新 更多