附加带退格的字符串时,从文本文件中删除字符

sɐu*_*qɐp 1 .net c# streamwriter text-files backspace

在C#中,是否可以将包含退格的字符串附加到文本文件中,并将所有退格视为"删除最后一个字符"操作?

例如我的文本文件:

这个文件有

两行

某种C#代码是这样的:

string str = "...\b\b\b\b\b\b\b\b\b\b\b\b\b one line."
myFile.Append(str);
Run Code Online (Sandbox Code Playgroud)

执行此代码后,文本文件如下所示:

这个文件有一行.

这些StreamWriterFile类似乎没什么帮助.

如果不在每个附加操作上读取和写入整个文件,我就无法轻易找到实现这一点的好方法,这可能会导致大文本文件出现严重的性能问题.我们的想法是使用这个新功能将日志语句集中写入文本文件.

我的第二个问题是如何处理windows风格的新行字符("\ r \n")?即一个退格键应删除整个单行换行符("\ r \n").

有关如何实现这一点的任何想法?

源代码将受到高度赞赏.

xan*_*tos 5

在"最一般的情况下"做"正确"是非常非常,非常困难..NET中没有直接的支持.让我们看看最先进的技术:

  • 有一个FileStream类...它是读/写.可悲的是,它不知道编码,它以字节为单位工作.所以没有UTF-8,也没有原生的Unicode.你看到你美丽的昵称s?un????q?p?它显然需要一些编码:-)

  • StreamReader并且StreamWriter可以被"连接到"一个FileStream.不幸的是它们是独立的(一个是只读的,一种是只写),以及它们可悲预缓冲器,从而使FileStream.Position不对应于在当前"读"字符StreamReader.这使得阅读与StreamReader"修复" StreamWriter相当复杂.

  • 即使我们有一个StreamReaderWriter,也会有点困难..NET适用于UTF-16 char,因此许多Unicode字符(例如,像笑脸一样的表情符号)由两个组成char......所以单个\b可能需要擦除一个或两个char(以及在UTF中的1到4个字节之间) 8),取决于它找到了什么.

  • 请注意,更复杂的表情符号(如 家族)由多个单个表情符号组成(4个unicode代码点,对应11个.net char,对应于UTF-8中的25个字节),但我们将忽略此问题

最简单的解决方案是将整个文件加载到string(或类似)内存中,修改它,然后将其重新写入磁盘.即使在这里,要注意行尾,可能是两个字符(\r\n),而"逻辑上"它们是单个字符(如果你在记事本中的一行开头并按下一个退格键,它将会完全擦除\r\n).但正如你已经注意到这个解决方案是"慢":-)

其他解决方案,有很多限制.正如我在评论中写的那样,你可以做相反的事情:保存Position前写,写,如果你需要纠正改变Position后面,重写,SetLength()截断多余的文件,如果存在.这将问题限制为只能修改您在当前会话中编写的文本部分的情况,通常只能修改文件的"最后"部分.

public static long WriteAppend(this FileStream fs, string str, Encoding enc)
{
    long pos = fs.Length;
    fs.Position = pos;
    byte[] bytes = enc.GetBytes(str);
    fs.Write(bytes, 0, bytes.Length);
    return pos;
}


public static long RewriteTruncate(this FileStream fs, long pos, string str, Encoding enc)
{
    fs.Position = pos;
    byte[] bytes = enc.GetBytes(str);
    fs.Write(bytes, 0, bytes.Length);
    fs.SetLength(pos + bytes.Length);
    return pos;
}
Run Code Online (Sandbox Code Playgroud)

使用:

int secs = 5;

using (var fs = new FileStream("Hello.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
{
    fs.WriteAppend("Beginning of the elaboration\r\n", Encoding.UTF8);

    long pos1 = fs.WriteAppend("Step 1\r\n", Encoding.UTF8);
    long pos2 = fs.WriteAppend($"Working 0\r\n", Encoding.UTF8);

    for (int i = 1; i < 10; i++)
    {
        Thread.Sleep(secs * 1000);
        fs.RewriteTruncate(pos2, $"Working {i}\r\n", Encoding.UTF8);
    }

    Thread.Sleep(secs * 1000);
    fs.RewriteTruncate(pos1, $"Finished working\r\n", Encoding.UTF8);
}
Run Code Online (Sandbox Code Playgroud)

在Notepad ++中保持打开输出文件并每隔几秒刷新一次.