C# 在文件中搜索字符串并获取字符串的行号

C# Search file for a string and get the string's line number

我整天都在做这个,我正在努力去做,我到处搜索,虽然有类似的问题,但没有答案。

我想做什么: 我正在尝试在一个文件中搜索多个字符串并接收行号,以便当用户希望在我的应用程序中更改所述字符串时,我的应用程序知道要用他们的字符串替换哪些行。

到目前为止我尝试过的: 我试过下面的代码,我的尝试是读取文件然后接收行号,但它似乎根本不起作用。

            var lines = File.ReadAllLines(filepath);
            foreach (var match in lines // File.ReadLines(filePath)
                            .Select((text, index) => new { text, lineNumber = index + 1 })
                            .Where(x => x.text.Contains("motd=")))
            {
                lines[match.lineNumber] = "motd=" + textBox1.Text;
                File.WriteAllLines(filepath, lines);
            }
        }

我希望上面的代码做的是在文件中找到字符串 "motd=",获取行号并尝试用用户输入的内容重写它。

但是,我收到此错误:“Index was outside the bounds of the array”。

我认为 for 循环在这里更有意义

var lines = File.ReadAllLines(filepath);
for (int i = 0; i < lines.Length; i++)
{
    if(lines[i].Contains("motd="))
    {
        lines[i] = "motd=" + textBox1.Text;
    }
}

File.WriteAllLines(filepath, lines);

你的代码有几个问题是你在循环中写出文件并且你将索引递增 1 这将指向数组中的错误行并导致你得到的异常如果最后一行包含您要搜索的文本。

应该注意的是,如果您正在处理一个非常大的文件,这可能会占用大量内存。在那种情况下,我会一次读取一行并将它们写到一个临时文件中,然后删除原始文件并在最后重命名临时文件。

var tempFile = Path.GetTempFileName();
using (var file = File.OpenWrite(tempFile))
using (var writer = new StreamWriter(file))
{
    foreach (var line in File.ReadLines(filepath))
    {
        if (line.Contains("motd="))
        {
            writer.WriteLine("motd=" + textBox1.Text);
        }
        else
        {
            writer.WriteLine(line);
        }
    }
}

File.Delete(filepath);
File.Move(tempFile, filepath);

您在每次迭代时都在编写文件,这毫无意义,而且做 select/where/index 事情很奇怪。

既然你在做 Where 你必须遍历每一行,那么为什么不省去麻烦而直接遍历所有内容呢?

var lines = File.ReadAllLines(filepath);
for(int i = 0; i < lines.Length; i++)
{
    if(lines[i].Contains("motd="))
    {
        lines[i] = "motd=" + textBox1.Text;
    }
}

File.WriteAllLines(filepath, lines);

这样会更快,使用更少的内存,并处理非常大的文件,但您需要写入一个新文件:

File.WriteAllLines(filepath2,
  File
    .ReadLines(filepath)
    .Select(x=>x.Contains("motd=")?"motd="+TextBox1.Text:x));

它使用 ReadLines 来尽可能地读取每一行,而不是读取整个文件并在一个步骤中将其分成几行。因此它会以您的文件系统可以读取的速度处理它,处理该行,然后写入结果。

完整的替换看起来像这样:

var filepath2= Path.GetTempFileName();
File.WriteAllLines(filepath2,
  File
    .ReadLines(filepath)
    .Select(x=>x.Contains("motd=")?"motd="+TextBox1.Text:x));
File.Delete(filepath);
File.Move(filepath2, filepath);

做多值:

var filepath2= Path.GetTempFileName();
File.WriteAllLines(filepath2,
  File
    .ReadLines(filepath)
    .Select(x=> {
      if (x.Contains("motd=")) return "motd="+TextBox1.Text;
      if (x.Contains("author=")) return "author="+TextBox2.Text;
      return x;
    }));
File.Delete(filepath);
File.Move(filepath2, filepath);

或者将替换逻辑移动到它自己的函数中:

string ReplaceTokens(string src)
{
  if (src.Contains("motd=")) return "motd="+TextBox1.Text;
  if (src.Contains("author=")) return "author="+TextBox2.Text;
  return src;
}
var filepath2= Path.GetTempFileName();
File.WriteAllLines(filepath2,
  File
    .ReadLines(filepath)
    .Select(ReplaceTokens));
File.Delete(filepath);
File.Move(filepath2, filepath);