winforms 为winform快速加载巨大的txt文件

jvlzgdj9  于 2023-02-16  发布在  其他
关注(0)|答案(1)|浏览(175)

我打算做一个僧伽罗文英语字典。所以我有一个文件,其中包含僧伽罗文含义的每一个英语单词。所以我想加载它,而形式是加载。所以我添加了以下命令,以获得所有文件内容的字符串变量。所以我用以下命令在FormLoad方法,

private string DictionaryWords = "";

private string ss = null;

...

private void Form1_Load(object sender, EventArgs e)
{
    this.BackColor = ColorTranslator.FromHtml("#AFC3E0");

    string fileName = @"SI-utf8.Txt";

    using (StreamReader sr = File.OpenText(fileName))
    {
        while ((ss = sr.ReadLine()) != null)
        {
            DictionaryWords += ss;
        }
    }
}

但不幸的是,该txt文件有130000+行,它的大小超过5MB。所以我的winform没有加载。
见图像

我需要加载这个更快的winform使用REGEX形式得到正确的含义,为每一个英语单词..谁能告诉我一个方法来做到这一点。我尝试了一切。
加载这个巨大的文件到我的项目内15多少,需要使用正则表达式查找每个英语单词。

wljmcqd8

wljmcqd81#

好吧,代码太少了。我怀疑

DictionaryWords += ss;

是重罪犯追加字符串130000次,这意味着 * 重新创建 * 相当长的字符串 * 一遍又一遍 * 可以很好地让系统屈服,但我没有严格的证明(我在评论中询问了DictionaryWords)。
这就是为什么让我试着从头开始解决这个问题。

  • 我们有一个SI-utf8.Txt的(长)字典。
  • 我们应该在不冻结UI的情况下加载字典。
  • 我们应该用这本词典来翻译英语课文。

我有这样的东西:

using System.IO;
using System.Linq;
using System.Threading.Tasks;

...

// Loading dictionary (async, since dictionary can be quite long)
// static: we want just one dictionary for all the instances
private static readonly Task<IReadOnlyDictionary<string, string>> s_Dictionary = 
  Task<IReadOnlyDictionary<string, string>>.Run(() => {
    char[] delimiters = { ' ', '\t' };

    IReadOnlyDictionary<string, string> result = File
      .ReadLines(@"SI-utf8.Txt")
      .Where(line => !string.IsNullOrWhiteSpace(line))
      .Select(line => line.Split(delimiters, StringSplitOptions.RemoveEmptyEntries))
      .Where(items => items.Length == 2)
      .ToDictionary(items => items[0], 
                    items => items[1], 
                    StringComparer.OrdinalIgnoreCase);

    return result;
  });

然后我们需要一个翻译部分:

// Let it be the simplest regex: English letters and apostrophes;
// you can improve it if you like
private static readonly Regex s_EnglishWords = new Regex("[A-Za-z']+");

// Tanslation is async, since we have to wait for dictionary to be loaded
private static async Task<string> Translate(string englishText) {
  if (string.IsNullOrWhiteSpace(englishText))
    return englishText;

  var dictionary = await s_Dictionary;

  return s_EnglishWords.Replace(englishText,
    match => dictionary.TryGetValue(match.Value, out var translation) 
      ? translation   // if we know the translation
      : match.Value); // if we don't know the translation
}

用法:

// Note, that button event should be async as well
private async void button1_Click(object sender, EventArgs e) {
  TranslationTextBox.Text = await Translate(OriginalTextBox.Text);
}
    • 编辑:**因此,DictionaryWordsstring,因此
DictionaryWords += ss;

是一个 * felon *。请不要在(深度)循环中追加string:每个append * 重新创建 * 字符串,这是很慢的。如果你坚持循环,使用StringBuilder

// Let's pre-allocate a buffer for 6 million chars
StringBuilder sb = new StringBuilder(6 * 1024 * 1024);

using (StreamReader sr = File.OpenText(fileName))
{
    while ((ss = sr.ReadLine()) != null)
    {
        sb.Append(ss);
    }
}

DictionaryWords = sb.ToString();

或者,为什么要循环呢?让. net来为您做这些工作:

DictionaryWords = File.ReadAllText(@"SI-utf8.Txt");
    • 编辑2:**如果实际文件大小不是 * 那么大 *(只有DictionaryWords += ss; * 一个人 * 会破坏乐趣),您可以坚持使用简单的同步解决方案:
private static readonly Regex s_EnglishWords = new Regex("[A-Za-z']+");

private static readonly IReadOnlyDictionary<string, string> s_Dictionary = File
  .ReadLines(@"SI-utf8.Txt")
  .Where(line => !string.IsNullOrWhiteSpace(line))
  .Select(line => line.Split(new char[] { ' ', '\t' },
     StringSplitOptions.RemoveEmptyEntries))
  .Where(items => items.Length == 2)
  .ToDictionary(items => items[0], 
                items => items[1], 
                StringComparer.OrdinalIgnoreCase);

private static string Translate(string englishText) {
  if (string.IsNullOrWhiteSpace(englishText))
    return englishText;

  return s_EnglishWords.Replace(englishText,
    match => s_Dictionary.TryGetValue(match.Value, out var translation) 
      ? translation 
      : match.Value);
}

那么用法就很简单了:

// Note, that button event should be async as well
private void button1_Click(object sender, EventArgs e) {
  TranslationTextBox.Text = Translate(OriginalTextBox.Text);
}

相关问题