如何创建由“开始”和“停止”按钮控制的CSV文件

本文关键字:停止 按钮 控制 文件 CSV 开始 何创建 创建 | 更新日期: 2023-09-27 18:00:25

我想设计一个windows窗体应用程序,将我的数据(约70k值)放在一个数组中,以便在最短的时间内将其传输到csv文件,csv文件路径和名称由windows窗体应用程序给定。

数据传输仅在第一个名为"开始"的按钮被按下时完成,而当第二个按钮"停止"被按下时,无论值的数量如何,数据传输都应该停止。

这是代码:

public static void Write(double[] data, string outputPath)
{ 
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < data.GetLength(0); i++)
    {
        sb.AppendLine(string.Join(",", data[i]));
    }
    File.WriteAllText(outputPath, sb.ToString());
}

这是我正在使用的函数,它有一个数组varibale dscaledData。我想从这个数组中获取值,并将其存储在csv文件中

Write(dScaledData, @csvadd);

@部分显示带有名称的csv路径存储在dscaledData变量中的数据值非常大,大约70k

如何创建由“开始”和“停止”按钮控制的CSV文件

您希望使用停止按钮以某种方式中断写入循环。但事实上,它将继续运行,并确实阻塞ui线程。因此,您需要在不同的线程中运行写循环。。

在.NET中有多种方法可以实现,例如Task.FactorythreadsBackgroundWorker

以下是一个使用Task.Factory:的简单但有效的实现

我们创建了一个类级变量stopped,我们从Buttons中设置并重置它。还有其他更复杂的方法可以取消Task,请参阅此处,但这已经足够了。。

对于我的测试,我还创建了伪数据。。

private void cb_Stop_Click(object sender, EventArgs e)
{  stopped = true;   // this will be checked in our output loop   }
private void cb_Start_Click(object sender, EventArgs e)
{
    stopped = false;
    // create my test data..
    List<double> data = new List<double>();
    for (int i = 0; i < 10000000; i++) data.Add((i+ 1d) / i * 1d );
    string filename = "D:''xxxxx.txt";
    // this is an optional callback to provide feedback. 
    // It obviuosly slows things down greatly..
    Action<int> callback = (value) => st_lines.Invoke(new Action(() 
                         => st_lines.Text = value + " lines written.."));
    // now we start the write loop in another task..
    // ..passing in our data and (optinally) the callback
    Task myFirstTask = Task.Factory.StartNew(() 
                     => Write(data.ToArray(), filename, callback));
}
static bool stopped = true;   // our flag
public static void Write(double[] data, string outputPath, Action<int> aCallback)
{    // your write loop
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < data.GetLength(0); i++)
    {
        if (stopped) break;   // our new test
        sb.AppendLine(string.Join(",", data[i]));
        aCallback( i );       // optional callback
    }
    File.WriteAllText(outputPath, sb.ToString());
}

关于定时情况的一些注意事项:

StringBuilder添加70k行应该不会花费很多时间。看看我的代码:我必须将测试数据拖动到10M行,才能按下机器上的停止按钮!

也许数据的创建是瓶颈,也许是写入磁盘。。?或者可能没有瓶颈??在决定实现之前,您应该了解这一点!

如果其他部分被识别为瓶颈,您将不得不相应地更改代码以脱离其他循环。。

我添加了回调机制,这样您就可以看到如何将有关任务进度的信息带回UI线程。它应该帮助用户决定停止任务是否有意义。。

但是添加回调会大大降低速度,所以不必为每一行调用它,而是可以这样做:if (i % 1000 == 0 ) aCallback(i);,并且每1000行只更新进度标签(当然也可以是ProgressBar)。

您需要使用BackgroundWorker来完成此操作。这正是你所需要的。

不要使用File.WriteAllText,而是在工作线程中使用File.WitLine。

在我看来,70k行并不多,如果你的数据量在未来没有大幅增长,除非你用Thread.Sleep() 手动暂停编写器线程,否则人类将无法启动/停止