搜索行时覆盖 txt 文件中的行

Overwriting lines in a txt file while searching for the lines

我正在使用 C# 开发视频游戏。我在 .txt 文件中有一个用户列表,其中包含他们的硬币数量,我希望在他们保存时覆盖他们的数量。我不知道如何在没有 "file already being used" 异常的情况下在 SteamReader 中使用 SteamWriter。基本上,我需要搜索用户名,如果找到,则用相同的用户名和新的硬币数量覆盖现有行。所有硬币数量均为“0000”格式(0010、0199 等),因此我可以使用 Substring 和 length 轻松查找和加载硬币数量。

这是我尝试使用的代码:

StreamReader sr = new StreamReader("C:\FakeFilePath");
String line;
try
{
  line = sr.ReadLine();
  while (line != null)
  {
     if (line.Contains(users[m.GetInt(0)].username))
     {
        using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\FakeFilePath", false))
        {
            file.WriteLine("\n" + users[m.GetInt(0)].username + " " + (users[m.GetInt(0)].rupees).ToString("D4"));
            file.Close();
        }
     }
     line = sr.ReadLine();
  }
}
finally
{
    sr.Close();
}

非常感谢任何帮助。

谢谢, 迪斯马斯盖伊

您可能应该按照评论者 Jonesy 的建议,通过简单地重写整个文件来做到这一点。文本文件可能相对较小,可能小于单个磁盘块(通常大小为 4K,但可能因文件系统配置而异),并且重写整个文件实际上与覆盖特定位置一样快。


如果您确实坚持只尝试覆盖特定位置,则需要一种可靠的方法来计算要写入的文件中的位置,然后您需要在写入之前设置 StreamWriter.BaseStream 对象的位置新数据。您还需要使用 read/write 访问权限打开文件一次,或者打开一次文件进行读取以找到位置,然后在再次打开文件进行写入之前将其关闭。

计算文件中位置的最简单方法是采用固定大小的字符编码,例如ASCII 或 UTF16。对于 ASCII,文件中的偏移量(以字节为单位)将与字符数相同;使用UTF16,它将是字符数的两倍。

注意每一行也必须有固定的长度;也就是说,您将用户名以及硬币数量存储在该行的固定宽度字段中。所以文件可能看起来像这样:

Username1     0001
User24        0117
SallyDoe999   0037

注意:上面每行20个字符:名字14个字符,硬币数4个字符,当然还有换行的两个字符。

例如,假设您将数据存储为 ASCII:

string fileName = "C:\FakeFilePath";

using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite))
using (StreamReader sr = new StreamReader(stream, Encoding.ASCII))
using (StreamWriter writer = new StreamWriter(stream, Encoding.ASCII))
{
    int lineCount = 0;
    String line;

    while ((line = sr.ReadLine()) != null)
    {
        if (line.Contains(users[m.GetInt(0)].username))
        {
            // Offset is the offset of the line itself, plus
            // the length of the name field (the name field doesn't
            // need to be written because it's already the right
            // value!)
            int byteOffset = (lineCount * 20) + 14;

            writer.BaseStream.Position = byteOffset;
            writer.Write(users[m.GetInt(0)].rupees.ToString("D4"));

            break;
        }

        lineCount++;
    }
}

如您所见,这需要付出很多努力,尤其是当您不得不更改文件格式时。那里有很多挑剔的 "has to be just right" 代码,它当然会大大限制您在文件格式方面的选择。我希望您能看到在需要更改时将整个文件重新写出来的智慧。 :)