【问题标题】:Issues with file splitting with c#使用 c# 进行文件拆分的问题
【发布时间】:2015-12-29 18:24:38
【问题描述】:

我一直在尝试制作一个程序,将较大的文本文件拆分成更小的部分,以便更易于使用。

我目前有两个问题,无法弄清楚发生了什么。

问题 1:后台工作人员有时会触发多次。我似乎无法弄清楚它决定运行的原因或次数。它将运行拆分并在最终文件上似乎循环回到开始工作并再次运行它。它还会触发多个已完成的工作任务。更复杂的是,如果我将拆分的文件数设置为不同的数字,我可以获得后台工作人员似乎触发的不同次数,但它与文件数没有直接关系。有时相同数量的文件会导致后台工作程序只触发一次,有时会触发多次。

问题 2:有时拆分不会创建所有文件。如果我运行一些文件,它将创建前两个文件,然后删除其余文件。似乎只有当我将数字设置为 3 个要拆分的文件时才会发生。如果我计算行数并将其相加,它应该是正确的。所以我不确定那里发生了什么。

调用线程

private void StartSplit()
    {
        if (int.TryParse(NumberOfFilesTB.Text, out _numberOfFiles))
        {
            if (bg.IsBusy)
            {
                ((MainWindow)Application.Current.MainWindow).SetStatus("Warning",
                    "Please only run one split process at a time.");
                return;
            }

            ((MainWindow)Application.Current.MainWindow).DisplayAlert(
                "Split is running, you will receive an alert when it has finished. You may use other tools while the split is running.");

            var args = new List<string> { _filepath, _includeHeaders.ToString(), _numberOfFiles.ToString() };
            bg.DoWork += bg_DoWork;
            bg.WorkerReportsProgress = true;
            bg.ProgressChanged += ProgressChanged;
            bg.RunWorkerCompleted += bg_RunWorkerCompleted;
            bg.WorkerSupportsCancellation = true;
            bg.RunWorkerAsync(args);
            ProcessText.Text = "Running split process";
        }
        else
        {
            ((MainWindow)Application.Current.MainWindow).SetStatus("Warning", "Please enter a number for number of files");
        }
    }

后台线程

  private void bg_DoWork(object sender, DoWorkEventArgs e)
    {
        var args = e.Argument as List<string>;
        string filepath = args[0];
        string includeHeaders = args[1];
        int numberOfFiles = Convert.ToInt32(args[2]);
        int numberOfRows = _lineCount / numberOfFiles;
        _tempath = Path.GetDirectoryName(_filepath);
        Directory.CreateDirectory(_tempath+"\\split");

        if (includeHeaders == "True")
        {
            using (var reader = new StreamReader(File.OpenRead(filepath)))
            {
                _lines.Clear();
                _header = reader.ReadLine();
                _lines.Add(_header);

                for (int i = 0; i < _lineCount; i++)
                {

                    if (bg.CancellationPending)
                    {
                        e.Cancel = true;
                        break;
                    }

                    int percentage = (i + 1) * 100 / _lineCount;

                    bg.ReportProgress(percentage);

                    _lines.Add(reader.ReadLine());

                    if (i % numberOfRows == 0)
                    {
                        _counter++;
                        Debug.WriteLine(i);

                        if (i == 0)
                        {
                            //skip first iteration 
                            _counter = 0;
                            continue;

                        }
                        _output = _tempath + "\\" + "split\\" + _fileNoExt + "_split-" + _counter + _fileExt;
                        _filesMade.Add(_output);
                        File.WriteAllLines(_output, _lines.ConvertAll(Convert.ToString));
                        _lines.Clear();
                        _lines.Add(_header);
                    }
                }
            }
        }
        else
        {
            using (var reader = new StreamReader(File.OpenRead(filepath)))
            {
                _lines.Clear();
                _header = reader.ReadLine();
                _lines.Add(_header);
                for (int i = 0; i < _lineCount; i++)
                {
                    if (bg.CancellationPending)
                    {
                        e.Cancel = true;
                        break;
                    }

                    int percentage = (i + 1) * 100 / _lineCount;
                    bg.ReportProgress(percentage);
                    _lines.Add(reader.ReadLine());

                    if (i % numberOfRows == 0)
                    {
                        _counter++;

                        if (i == 0)
                        {
                            //skip first iteration
                            _counter = 0;
                            continue;
                        }
                        string output = _tempath + "\\" + "split\\" + _fileNoExt + "_split-" + _counter + _fileExt;
                        _filesMade.Add(_output);
                        File.WriteAllLines(output, _lines.ConvertAll(Convert.ToString));
                        _lines.Clear();

                    }
                }
            }

        }
    }

运行 Worker 已完成

private void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Cancelled)
        {
            StopSplit();
            _filesMade.Clear();
            ProcessText.Text = "Split cancelled";
            return;
        }
        _filesMade.Clear();
        ProcessText.Text = "Split has completed, click here to open the directory";
    }

【问题讨论】:

  • 您正在订阅活动,但从未退订。
  • 糟糕的程序设计。您有 2 个部分的代码几乎相同。目前正在寻找失败原因#2...
  • 如果您对我可以改进的地方有任何反馈,我会全力以赴。我对此还很陌生,事件和最佳编程实践对我来说仍然是一个新概念。
  • 以 _ 开头的变量名也是不好的做法。如果它们是成员变量,我建议使用 m_,我更喜欢并使用它。
  • 此外,您应该避免使用“全局”变量。尽可能或明智地缩小变量的范围。首选局部变量。如果其他地方需要变量,请将其作为参数传递给函数,这更困难但更安全。

标签: c# multithreading backgroundworker


【解决方案1】:

我敢打赌,您的 BgW 是您班级的成员...
在 Startsplit() 中,每次执行此函数时都会添加一个新回调。
这就是它运行多次的原因。

晚餐后的其他答案。

晚餐结束...
您的计数方法在多个方面存在缺陷:
1)如果您丢失了文件,我敢打赌它是最后一个。例如。 30 行,3 个文件:
i % numberOfRows 在 i=0、10、20 处为零,但 i 未达到 30。
2)您缺少行,例如31 行 4 个文件:
文件保存在 i=7, 14, 21, 28。缺少第 29-31 行。

我建议你使用嵌套的 for 循环,外层用于文件,内层用于行,并改进你的计算。并将所有列表和计数器放入函数中!
我希望你能欣赏我的回答。我讨厌在平板电脑上打字。但也不想为此启动我的计算机... ;-)

【讨论】:

  • 正确。我将 BgW 声明为该类的成员,这样我就可以调用它以取得进展或在需要时取消该 BgW。我不确定如何在方法中使用 BgW 并且仍然能够从不同的方法调用它,因为它不会存在于该范围之外,对吗?
  • @Tbooty,是的,正确,所以你也应该在你创建它的地方配置它。
猜你喜欢
  • 2016-04-02
  • 1970-01-01
  • 1970-01-01
  • 2018-11-20
  • 1970-01-01
  • 2011-04-26
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多