C# 添加带退格的字符串时,从文本文件中删除字符
是否可以将包含backspaces的字符串附加到文本文件中,并将其中的所有backspaces视为“remove last char”操作 例如,我的文本文件: 此文件已被删除 两行 类似这样的C代码:C# 添加带退格的字符串时,从文本文件中删除字符,c#,.net,text-files,streamwriter,backspace,C#,.net,Text Files,Streamwriter,Backspace,是否可以将包含backspaces的字符串附加到文本文件中,并将其中的所有backspaces视为“remove last char”操作 例如,我的文本文件: 此文件已被删除 两行 类似这样的C代码: string str = "...\b\b\b\b\b\b\b\b\b\b\b\b\b one line." myFile.Append(str); 执行此代码后,文本文件如下所示: string str = "...\b\b\b\b\b\b\b\b\b\b\b\
string str = "...\b\b\b\b\b\b\b\b\b\b\b\b\b one line."
myFile.Append(str);
执行此代码后,文本文件如下所示:
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”)?i、 e.一个退格应删除整个换行符序列(“\r\n”)
关于如何实现这一点有什么想法吗
非常感谢您的源代码。在“最一般情况下”正确地执行它非常非常困难。NET中没有直接的支持。让我们看看最新技术:
- 有一个
类。。。它是读/写的。可悲的是,它不知道编码,它以字节为单位工作。因此本机没有UTF-8和Unicode。你看到你漂亮的尼克了吗?它显然需要一些编码:-)FileStream
和StreamReader
可以“连接”到StreamWriter
。。。遗憾的是,它们是分开的(一个是只读的,一个是写的),遗憾的是它们预缓冲,因此FileStream
与FileStream.Position
中当前的“read”字符不对应。这使得使用StreamReader
进行读取,然后使用StreamReader
进行“就地”更正变得相当复杂StreamWriter
- 即使我们有一个
,也会有点困难。NET与UTF-16StreamReaderWriter
s配合使用,因此许多Unicode字符(类似表情符号在“最一般情况下”正确使用)非常非常困难。在.NET中没有直接支持。让我们看看最新技术:char
- 有一个
类…它是读/写的。遗憾的是,它不知道编码,它是以字节为单位工作的。所以没有UTF-8,也没有Unicode本机。你可以看到你美丽的尼克FileStream
?它显然需要一些编码:-)sɐunıɔןqɐp
和StreamReader
可以“连接”到StreamWriter
。。。遗憾的是,它们是分开的(一个是只读的,一个是写的),遗憾的是它们预缓冲,因此FileStream
与FileStream.Position
中当前的“read”字符不对应。这使得使用StreamReader
进行读取,然后使用StreamReader
进行“就地”更正变得相当复杂StreamWriter
- 即使我们有一个
,也会有点困难。NET与UTF-16StreamReaderWriter
s一起工作,因此许多Unicode字符(类似于的表情符号)都是基于和基于,我编写了这个原型char
类,它将字符串(要附加的)计算为初始退格字符序列和剩余字符串(没有任何退格) 如果存在初始退格,程序将根据初始退格的数量(以非常简单的方式)截断FileLogger
对象,然后追加剩余的字符串FileStream
不幸的是,这个解决方案不考虑任何代码> > R\N\/Cord-NeXLINE序列,它应该由一个单一的退格空间移除,既可以从<代码> FielestRAM和附加的字符串中删除。现在,需要两个退格来移除一个Windows样式的新行字符序列。
输出(test.log文件): 阿克斯 基于并基于此,我编写了这个原型using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; namespace Example { public static class FileLogger { public static bool IsStarted { get; private set; } public static Encoding Encoding { get; private set; } public static string LogFilePath { get; private set; } private static FileStream FS; private static int BytesPerChar; private static readonly object Locker = new object(); public static void Start(string logFilePath, Encoding encoding = null) { lock (Locker) { if (IsStarted) return; LogFilePath = logFilePath; Encoding = encoding ?? Encoding.UTF8; if (File.Exists(LogFilePath)) File.SetAttributes(LogFilePath, FileAttributes.Normal); FS = new FileStream(LogFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 4096, FileOptions.RandomAccess); FS.SetLength(0); FS.Flush(); BytesPerChar = Encoding.UTF8.GetByteCount(new[] { 'A' }); IsStarted = true; } } public static void Close() { lock (Locker) { if (!IsStarted) return; try { FS?.Close(); } catch { } FS = null; IsStarted = false; } } public static void WriteToFile(string text) { lock (Locker) { if (string.IsNullOrEmpty(text)) return; if (!text.Contains('\b')) { FS.Position = FS.Length; byte[] bytes = Encoding.GetBytes(text); FS.Write(bytes, 0, bytes.Length); FS.Flush(); return; } // Evaluates the the string into initial backspaces and remaining text to be appended: EvaluateText(text, out int initialBackspaces, out string remainingText); // If there are no initial backspaces after evaluating the string, just append it and return: if (initialBackspaces <= 0) { if (string.IsNullOrEmpty(remainingText)) return; FS.Position = FS.Length; byte[] bytes = Encoding.GetBytes(remainingText); FS.Write(bytes, 0, bytes.Length); FS.Flush(); return; } // First process the initial backspaces: long pos = FS.Length - initialBackspaces * BytesPerChar; FS.Position = pos > 0 ? pos : 0; FS.SetLength(FS.Position); // Then write any remaining evaluated text: if (!string.IsNullOrEmpty(remainingText)) { byte[] bytes = Encoding.GetBytes(remainingText); FS.Write(bytes, 0, bytes.Length); } FS.Flush(); return; } } public static void EvaluateText(string text, out int initialBackspaces, out string remainingTextToAppend) { initialBackspaces = 0; StringBuilder sb = new StringBuilder(); foreach (char ch in text) { if(ch == '\b') { if (sb.Length > 0) sb.Length--; else initialBackspaces++; } else sb.Append(ch); } remainingTextToAppend = sb.ToString(); } } }
类,它将字符串(要追加的)计算为初始退格字符加上剩余字符串(没有任何退格)的序列 如果存在初始退格,程序将根据初始退格的数量(以非常简单的方式)截断FileLogger
对象,然后追加剩余的字符串FileStream
不幸的是,这个解决方案不考虑任何代码> > R\N\/Cord-NeXLINE序列,它应该由一个单一的退格空间移除,既可以从<代码> FielestRAM和附加的字符串中删除。现在,需要两个退格来移除一个Windows样式的新行字符序列。
输出(test.log文件): 阿克斯using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; namespace Example { public static class FileLogger { public static bool IsStarted { get; private set; } public static Encoding Encoding { get; private set; } public static string LogFilePath { get; private set; } private static FileStream FS; private static int BytesPerChar; private static readonly object Locker = new object(); public static void Start(string logFilePath, Encoding encoding = null) { lock (Locker) { if (IsStarted) return; LogFilePath = logFilePath; Encoding = encoding ?? Encoding.UTF8; if (File.Exists(LogFilePath)) File.SetAttributes(LogFilePath, FileAttributes.Normal); FS = new FileStream(LogFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 4096, FileOptions.RandomAccess); FS.SetLength(0); FS.Flush(); BytesPerChar = Encoding.UTF8.GetByteCount(new[] { 'A' }); IsStarted = true; } } public static void Close() { lock (Locker) { if (!IsStarted) return; try { FS?.Close(); } catch { } FS = null; IsStarted = false; } } public static void WriteToFile(string text) { lock (Locker) { if (string.IsNullOrEmpty(text)) return; if (!text.Contains('\b')) { FS.Position = FS.Length; byte[] bytes = Encoding.GetBytes(text); FS.Write(bytes, 0, bytes.Length); FS.Flush(); return; } // Evaluates the the string into initial backspaces and remaining text to be appended: EvaluateText(text, out int initialBackspaces, out string remainingText); // If there are no initial backspaces after evaluating the string, just append it and return: if (initialBackspaces <= 0) { if (string.IsNullOrEmpty(remainingText)) return; FS.Position = FS.Length; byte[] bytes = Encoding.GetBytes(remainingText); FS.Write(bytes, 0, bytes.Length); FS.Flush(); return; } // First process the initial backspaces: long pos = FS.Length - initialBackspaces * BytesPerChar; FS.Position = pos > 0 ? pos : 0; FS.SetLength(FS.Position); // Then write any remaining evaluated text: if (!string.IsNullOrEmpty(remainingText)) { byte[] bytes = Encoding.GetBytes(remainingText); FS.Write(bytes, 0, bytes.Length); } FS.Flush(); return; } } public static void EvaluateText(string text, out int initialBackspaces, out string remainingTextToAppend) { initialBackspaces = 0; StringBuilder sb = new StringBuilder(); foreach (char ch in text) { if(ch == '\b') { if (sb.Length > 0) sb.Length--; else initialBackspaces++; } else sb.Append(ch); } remainingTextToAppend = sb.ToString(); } } }
因此,您只想在附加到文件之前删除文件的最后n个字符?实际上,该字符串可能包含出现退格之前的字符。如所提供的示例中所示,字符串开头有三个点(.)字符。但该字符串确实将始终附加到文本文件中。(我已经编辑了这个示例,让它更清晰)简短的答案是否定的。长的答案是您必须使用某种描述的位置
或
搜索
和一些好的老式文件流来构建自己的功能coding@TheGeneral考虑到编码,可能比使用文件流
文件流更复杂:-)(例如,参见提问者使用的刻痕)。遗憾的是,.NET中没有统一的
,因此修改编码的文本文件变得很痛苦。@xanatos非常好,所以您只想在附加到文件之前删除文件的最后n个字符?实际上,字符串中可能包含空格之前的字符。如所提供的示例中所示,有开头有三个点(.)字符StreamReaderWriter
- 有一个