作者:谷智精源 | 来源:互联网 | 2022-12-10 12:41
在C#中,是否可以将包含退格的字符串附加到文本文件中,并将所有退格视为"删除最后一个字符"操作?
例如我的文本文件:
这个文件有
两行
某种C#代码是这样的:
string str = "...\b\b\b\b\b\b\b\b\b\b\b\b\b one line."
myFile.Append(str);
执行此代码后,文本文件如下所示:
这个文件有一行.
这些StreamWriter
和File
类似乎没什么帮助.
如果不在每个附加操作上读取和写入整个文件,我就无法轻易找到实现这一点的好方法,这可能会导致大文本文件出现严重的性能问题.我们的想法是使用这个新功能将日志语句集中写入文本文件.
我的第二个问题是如何处理windows风格的新行字符("\ r \n")?即一个退格键应删除整个单行换行符("\ r \n").
有关如何实现这一点的任何想法?
源代码将受到高度赞赏.
1> xanatos..:
在"最一般的情况下"做"正确"是非常非常,非常困难..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;
}
使用:
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);
}
在Notepad ++中保持打开输出文件并每隔几秒刷新一次.