如何从没有包含数据的文本文件中读取?
How to read from a text file which does not have consisted data?
我有一个文本文件,其中存储了有关生产信息和过程的信息。该过程由几个阶段组成,例如 Stripping
、Cleaning
、Paint
等。这些阶段存储的日期可能是 expected date
、start date
、finished date
, delay date
.
示例 .txt 文件:
567,Eindhoven,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(@"..\..7.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
是连接到 dataGridView1
的 DataTable
作为 DataSource
。
我以前从未使用过文本文件,所以非常感谢您的帮助!
读取 semi-unstructured CSV 可能很棘手,您必须坚信 CSV 文件始终是正确的。例如,如果某个类别的其中一个日期拼写错误,例如……“Panint_s=28/05/2020”……在发布的数据中……那么,在下面的代码中,这种拼写错误不会引发任何类型的错误错误或消息,它永远不会被使用。所以,编码器要小心。下面是一种这样的“hacky”方法。
您可能遇到的一个问题是当前代码如何使用字符串数组 (string[]
)。这将使事情变得更加复杂。当代码到达 SomeCategory=SomeDate
点时,它很有用。下面,一个字符串数组用于这些拆分以获取类别的日期。在代码的其他地方,它使用 List<string>
来分隔数据中的行。当我们想要获取“特定”类别的日期时,这将有所帮助。更多内容在下方。
因此,给定一个 string
数据,如您显示的那样,string
是网格中的“单个”行,那么我会用逗号“拆分”该字符串”, ”。然后将字符串数组转换为List<string>
。它可能看起来像……
List<string> SplitRow = curRow.Split(',').ToList();
鉴于已发布的单行数据,此 List<string>
allData
可能类似于……
可以看出,我们将使用此 List<string>
来获取网格中前三个单元格的数据,并且当我们到达我们想要获取“最新”日期的代码部分时对于特定类别,我们可以“过滤”此 List<string>
以仅包含我们想要的类别。如果 allData
是上面的 List<string>
,那么要过滤列表以仅包含我们想要的类别,代码可能类似于...
String targetCategory = “Stripping”;
List<string> categoryData = allData.Where(x => x.Contains(targetCategory)).ToList();
这将产生一个 List<string>
categoryData
只有“剥离”类别。像下面...
使用此列表,我们可以遍历所有字符串,解析日期和 return 所有给定日期的最新日期。如果我们创建一个方法来 returns 这个日期字符串,那么我们可以使用它来为每一行分配网格中的每个类别列。
因此,采用 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
变量来比较日期并用作最新日期。我们将日期设置为“最小”值,我们将使用此“最小”日期来指示该类别在数据中没有日期。接下来是字符串数组splitArray
,用于在“=”字符上拆分每个字符串。
开始循环遍历列表中所有已过滤的字符串。在“=”字符上拆分字符串后,将进行检查以确保字符串中有日期。如果有日期字符串,那么该日期将被解析为 DateTime
对象以便于比较。如果日期解析成功,则代码将检查解析的日期是否为最新日期。如果解析的日期晚于当前 latestDate
,则会更新以反映这个更新的最新日期。
检查完所有日期后,代码将检查 latestDate
。如果 latestDate
仍然是“最小”值,那么这意味着没有找到该类别的日期并且空字符串是 returned,否则代码将 return 最新日期字符串.
如果代码循环遍历有很多行的数据中的每个字符串,那么当我们想要从特定类别中获取最新日期时,上述方法会派上用场。
因此,将其放在一起可能如下所示……
private void Import() {
List<string> allLines = File.ReadAllLines(@"D:\Test\CSV7.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<string>
。在发布的数据中,这将是列表中的单个字符串。接下来定义了一个 DataRow
dr
,我们将使用这一行来添加我们从数据中获得的值。另一个 List<string>
SplitRow
用于列表中的“每个”字符串。最后,一个 int
value
用于解析 int
值 SalesNr
和 Type
.
开始循环遍历所有数据中的每个字符串,从现有的 table
创建一个新的 DataRow
,然后用逗号“;”拆分当前字符串。进行检查以确保 SalesNr、PName 和 Type 至少有三 (3) 个值。解析 SalesNr
和 Type
值,然后将 PName
字符串值设置到新行中。然后,每个“类别”将使用上述方法为每个类别设置日期字符串。最后,该行被添加到 table
。注:代码中并非所有类别都填写
我希望这是有道理的。它很笨拙,但在我的测试中有效。祝你好运。
这就是我的做法。
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;
}
}
}
我有一个文本文件,其中存储了有关生产信息和过程的信息。该过程由几个阶段组成,例如 Stripping
、Cleaning
、Paint
等。这些阶段存储的日期可能是 expected date
、start date
、finished date
, delay date
.
示例 .txt 文件:
567,Eindhoven,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(@"..\..7.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
是连接到 dataGridView1
的 DataTable
作为 DataSource
。
我以前从未使用过文本文件,所以非常感谢您的帮助!
读取 semi-unstructured CSV 可能很棘手,您必须坚信 CSV 文件始终是正确的。例如,如果某个类别的其中一个日期拼写错误,例如……“Panint_s=28/05/2020”……在发布的数据中……那么,在下面的代码中,这种拼写错误不会引发任何类型的错误错误或消息,它永远不会被使用。所以,编码器要小心。下面是一种这样的“hacky”方法。
您可能遇到的一个问题是当前代码如何使用字符串数组 (string[]
)。这将使事情变得更加复杂。当代码到达 SomeCategory=SomeDate
点时,它很有用。下面,一个字符串数组用于这些拆分以获取类别的日期。在代码的其他地方,它使用 List<string>
来分隔数据中的行。当我们想要获取“特定”类别的日期时,这将有所帮助。更多内容在下方。
因此,给定一个 string
数据,如您显示的那样,string
是网格中的“单个”行,那么我会用逗号“拆分”该字符串”, ”。然后将字符串数组转换为List<string>
。它可能看起来像……
List<string> SplitRow = curRow.Split(',').ToList();
鉴于已发布的单行数据,此 List<string>
allData
可能类似于……
可以看出,我们将使用此 List<string>
来获取网格中前三个单元格的数据,并且当我们到达我们想要获取“最新”日期的代码部分时对于特定类别,我们可以“过滤”此 List<string>
以仅包含我们想要的类别。如果 allData
是上面的 List<string>
,那么要过滤列表以仅包含我们想要的类别,代码可能类似于...
String targetCategory = “Stripping”;
List<string> categoryData = allData.Where(x => x.Contains(targetCategory)).ToList();
这将产生一个 List<string>
categoryData
只有“剥离”类别。像下面...
使用此列表,我们可以遍历所有字符串,解析日期和 return 所有给定日期的最新日期。如果我们创建一个方法来 returns 这个日期字符串,那么我们可以使用它来为每一行分配网格中的每个类别列。
因此,采用 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
变量来比较日期并用作最新日期。我们将日期设置为“最小”值,我们将使用此“最小”日期来指示该类别在数据中没有日期。接下来是字符串数组splitArray
,用于在“=”字符上拆分每个字符串。
开始循环遍历列表中所有已过滤的字符串。在“=”字符上拆分字符串后,将进行检查以确保字符串中有日期。如果有日期字符串,那么该日期将被解析为 DateTime
对象以便于比较。如果日期解析成功,则代码将检查解析的日期是否为最新日期。如果解析的日期晚于当前 latestDate
,则会更新以反映这个更新的最新日期。
检查完所有日期后,代码将检查 latestDate
。如果 latestDate
仍然是“最小”值,那么这意味着没有找到该类别的日期并且空字符串是 returned,否则代码将 return 最新日期字符串.
如果代码循环遍历有很多行的数据中的每个字符串,那么当我们想要从特定类别中获取最新日期时,上述方法会派上用场。
因此,将其放在一起可能如下所示……
private void Import() {
List<string> allLines = File.ReadAllLines(@"D:\Test\CSV7.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<string>
。在发布的数据中,这将是列表中的单个字符串。接下来定义了一个 DataRow
dr
,我们将使用这一行来添加我们从数据中获得的值。另一个 List<string>
SplitRow
用于列表中的“每个”字符串。最后,一个 int
value
用于解析 int
值 SalesNr
和 Type
.
开始循环遍历所有数据中的每个字符串,从现有的 table
创建一个新的 DataRow
,然后用逗号“;”拆分当前字符串。进行检查以确保 SalesNr、PName 和 Type 至少有三 (3) 个值。解析 SalesNr
和 Type
值,然后将 PName
字符串值设置到新行中。然后,每个“类别”将使用上述方法为每个类别设置日期字符串。最后,该行被添加到 table
。注:代码中并非所有类别都填写
我希望这是有道理的。它很笨拙,但在我的测试中有效。祝你好运。
这就是我的做法。
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;
}
}
}