我正在做一个桌面应用程序使用的窗口形式与C#,我想使应用程序能够转置csv数据(使列成行)当用户导入文件,如何编写代码呢?这里是我的应用程序user when upload a CSV File的屏幕截图
我已经在导入按钮中编写了代码
private void btnImport_Click(object sender, System.EventArgs e)
{
try
{
if (txtCSVFolderPath.Text == "")
{
MessageBox.Show("The Folder Path TextBox cannot be empty.", "Warning");
return;
}
else if (txtCSVFilePath.Text == "")
{
MessageBox.Show("The File Path TextBox cannot be empty.", "Warning");
return;
}
else
{
ConnectCSV();
btnUpload.Enabled = true;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{ }
}
和connectcsv()类
public DataSet ConnectCSV()
{
DataSet ds = new DataSet();
string fileName = openFileDialogCSVFilePath.FileName;
CsvReader reader = new CsvReader(fileName);
ds = reader.RowEnumerator;
dGridCSVdata.DataSource = ds;
dGridCSVdata.DataMember = "TheData";
return ds;
}
最新消息:
所以我试着使用'StringBuilder',但没有任何效果,它有什么问题吗?或者有没有其他方法的想法?
public DataSet RowEnumerator
{
get
{
if (null == __reader)
throw new System.ApplicationException("I can't start reading without CSV input.");
__rowno = 0;
string sLine;
string sNextLine;
DataSet ds = new DataSet();
DataTable dt = ds.Tables.Add("TheData");
while (null != (sLine = __reader.ReadLine()))
{
while (rexRunOnLine.IsMatch(sLine) && null != (sNextLine = __reader.ReadLine()))
sLine += "\n" + sNextLine;
__rowno++;
DataRow dr = dt.NewRow();
string[] values = rexCsvSplitter.Split(sLine);
for (int i = 0; i < values.Length; i++)
{
values[i] = Csv.Unescape(values[i]);
if (__rowno == 1)
{
dt.Columns.Add(values[i].Trim());
}
else
{
if (Csv.CharNotAllowes(values[i]))
{
dr[i] = values[i].Trim();
}
}
}
if (__rowno != 1)
{
dt.Rows.Add(dr);
}
}
StringBuilder sb = new StringBuilder();// code I add for transpose the data table
for (int u = 0; u < dt.Columns.Count; u++)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
sb.Append(dt.Rows[i][u].ToString());
if (i < dt.Rows.Count - 1)
{
sb.Append(';');
}
}
sb.AppendLine();
}
File.WriteAllText("C:\\Users\\Desktop\\Output.csv", sb.ToString());
__reader.Close();
return ds;
}
}
1条答案
按热度按时间wydwbb8l1#
与其仅仅写一些代码来做转置,我认为更有用的是走一走我是如何得到答案的,因此相当长的答案。
在
RowEnumerator
属性中有很多内容,这使得它很难测试。因为问题主要是询问如何将一个DataTable
转置到另一个DataTable
,所以让我们将转置功能拉到它自己的方法中,或者更好的是它自己的类中,在那里可以隔离地测试它。注意,该类不依赖于任何特定的UI框架,这使得它更易于测试并且更易于重用。写一个只抛出异常的方法有什么意义呢?答案:现在我们已经有了方法签名,我们可以为这个方法编写一些单元测试,这样我们就可以定义我们期望它如何表现。如果你想在编写被测试的代码之前了解更多关于编写单元测试的方法,你需要的搜索词是“测试驱动开发”。
接下来,在你的解决方案中添加一个XUnit单元测试项目。你不一定要使用XUnit,还有其他的单元测试框架,比如NUnit和MSTest,它们都可以做这类事情。XUnit只是我个人的喜好。如果你以前没有用过它,可以看看它的文档,特别是入门指南。
将项目指涉加入至公寓测试项目,让它指涉包含
Transposer
类别的项目。将下列NuGet套件加入至公寓测试项目:(the最后两个不是必需的,但是我发现分析器非常有用,可以提供关于我是否遵循良好编码实践的反馈)。现在我们可以开始为
Transposer
类编写单元测试了。值得指出的是,在Assert步骤中,
actualOutput
(即DataTable
)似乎有一个Should()
方法,这实际上是FluentAssertions包中的一个扩展方法,它有许多这样的扩展方法,可以极大地简化编写复杂对象的Assert。这还不会生成,因为它引用了一个名为
TransposeTestData
的属性,我们还没有创建它。此属性将为我们的单元测试方法提供参数化测试数据,以便该方法可以使用多对输入和预期输出来运行。有关XUnit中参数化测试的更多信息,请参见Andrew Lock's blog。现在我们可以将
TransposeTestData
属性添加到TransposerTest
类中:这给了我们一个测试用例列表,每个测试用例都是一个对象数组,其中数组的元素对应于
TransposeTest
方法的每个参数,所以对于这个测试,每个对象数组都需要两个元素,第一个是我们想要转置的DataTable
,第二个是我们期望转置后的DataTable
的样子。我们还需要添加这个小的helper方法,它简化了在测试数据中创建
DataTable
的过程。我们现在可以构建并运行单元测试了,当然,它们会以
NotImplementedException
失败,因为我们还没有实现Transpose
方法。这可能看起来需要做很多工作,但这是值得花的时间,因为我们现在有了一个单元测试,它不仅定义了我们期望
Transpose
方法如何工作,而且还告诉我们它是否工作正确。我们在Transpose
方法中需要的逻辑很容易出错,我不介意承认我花了几次尝试才把它弄正确。实际上如果没有单元测试我可能已经放弃了。现在我们可以在
Transposer
类中实现Transpose
方法:因为我们有了单元测试,我们可以运行它来检查方法是否正确运行。一旦我们对它的正确运行感到满意,我们就可以从
RowEnumerator
属性调用它。我们可以转置dt
并将转置后的DataTable
添加到ds
,而不是将dt
添加到DataSet
ds
。例如,我希望这个答案能帮助您了解如何分离代码中的关注点,如何使代码更易于测试,以及如何测试代码。