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

How to create a CSV file controlled by Start- and Stop-Buttons

我想设计一个 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());
}

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

Write(dScaledData, @csvadd);

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

您想使用停止按钮以某种方式中断您的写入循环。但实际上,它将保持 运行ning 并确实阻塞 ui 线程。所以你需要运行在不同的线程中写循环..

在 .NET 中有多种方法可以做到这一点,例如Task.FactorythreadsBackgroundWorker.

这是一个使用 Task.Factory:

的简单但有效的实现

我们创建了一个 class 级别变量 stopped,我们从 Buttons 设置和重置它。还有其他更复杂的方法可以取消 Tasksee here,但这足以达到目的..

对于我的测试,我还创建了虚拟数据..

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());
}

关于时间情况的几点说明:

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

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

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

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

但是添加回调会使事情变慢很多,所以你可以这样做,而不是为每一行都调用它:if (i % 1000 == 0 ) aCallback(i); 并且只更新进度标签(或 ProgressBar , 当然) 每 1000 行.

为此您需要使用 BackgroundWorker。这正是您所需要的。

不要使用 File.WriteAllText,但在工作线程中使用 File.WriteLine。

在我看来 70k 行不是很多,如果你的数据量在未来不会大幅增长,人类将无法 start/stop 除非你人为地暂停 writer thread with a Thread.Sleep()