如何从 C# 中的文本文件中删除一行?

Posted

技术标签:

【中文标题】如何从 C# 中的文本文件中删除一行?【英文标题】:How to delete a line from a text file in C#? 【发布时间】:2010-10-14 17:03:54 【问题描述】:

我有一个问题:如何在 C# 中从文本文件中删除一行?

【问题讨论】:

他/她的意思是我猜如何以编程方式删除它。 【参考方案1】:

我意识到这已经很长时间了,但这对我有帮助,所以我想改进它。 Leonhard 的回答对我非常有用。但是,如果您的文本文件真的像我的一样大,StringBuilder 将给出内存不足错误。所以我改为这样使用它。创建一个新文件并写入其中。然后,您可以根据需要删除第一个文件。请注意, Line 变量确定文件将被删除到哪一行。您可以修改它以指定要删除的行的间隔。

void File_DeleteLine(int Line, string Path, string newPath)

    StreamReader reader = new StreamReader(Path);
    StreamWriter writer = new StreamWriter(newPath);
    int Countup = 0;
    while (!reader.EndOfStream)
    
        Countup++;
        if (Countup > Line)
        

            writer.WriteLine(reader.ReadLine());

        
        else
        
            reader.ReadLine();
        
    

【讨论】:

【参考方案2】:
string fileIN = @"C:\myTextFile.txt";
string fileOUT = @"C:\myTextFile_Out.txt";
if (File.Exists(fileIN))

    string[] data = File.ReadAllLines(fileIN);
    foreach (string line in data)
        if (!line.Equals("my line to remove"))
            File.AppendAllText(fileOUT, line);
    File.Delete(fileIN);
    File.Move(fileOUT, fileIN);

【讨论】:

【参考方案3】:

从多个文件中删除一段代码

为了扩展@Markus Olsson 的答案,我需要从多个文件中删除一段代码。我在核心项目中遇到瑞典字符问题,因此我需要安装 System.Text.CodePagesEncodingProvider nuget 包并使用 System.Text.Encoding.GetEncoding(1252) 而不是 System.Text.Encoding.UTF8。

    public static void Main(string[] args)
    
        try
        
            var dir = @"C:\Test";
            //Get all html and htm files
            var files = DirSearch(dir);
            foreach (var file in files)
            
                RmCode(file);
            
        
        catch (Exception e)
        
            Console.WriteLine(e.Message);
            throw;
        

    

    private static void RmCode(string file)
    
        string tempFile = Path.GetTempFileName();

        using (var sr = new StreamReader(file, Encoding.UTF8))
        using (var sw = new StreamWriter(new FileStream(tempFile, FileMode.Open, FileAccess.ReadWrite), Encoding.UTF8))
        
            string line;

            var startOfBadCode = "<div>";
            var endOfBadCode = "</div>";
            var deleteLine = false;

            while ((line = sr.ReadLine()) != null)
            
                if (line.Contains(startOfBadCode))
                
                    deleteLine = true;
                
                if (!deleteLine)
                
                    sw.WriteLine(line);
                

                if (line.Contains(endOfBadCode))
                
                    deleteLine = false;
                
            
        

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

    private static List<String> DirSearch(string sDir)
    
        List<String> files = new List<String>();
        try
        
            foreach (string f in Directory.GetFiles(sDir))
            
                files.Add(f);
            
            foreach (string d in Directory.GetDirectories(sDir))
            
                files.AddRange(DirSearch(d));
            
        
        catch (System.Exception excpt)
        
            Console.WriteLine(excpt.Message);
        

        return files.Where(s => s.EndsWith(".htm") || s.EndsWith(".html")).ToList();
    

【讨论】:

【参考方案4】:

要从文本文件中删除项目,首先将所有文本移动到列表中,然后删除您想要的任何项目。然后将存储在列表中的文本写入文本文件:

List<string> quotelist=File.ReadAllLines(filename).ToList();
string firstItem= quotelist[0];
quotelist.RemoveAt(0);
File.WriteAllLines(filename, quotelist.ToArray());
return firstItem;

【讨论】:

对于他们的 .NET 版本中没有 ReadAllLines() 或 WriteAllLines() 的“另一半”(好吧,另外 0.05%)呢?【参考方案5】:

我写了一个从文件中删除行的方法。

这个程序使用using System.IO

查看我的代码:

void File_DeleteLine(int Line, string Path)

    StringBuilder sb = new StringBuilder();
    using (StreamReader sr = new StreamReader(Path))
    
        int Countup = 0;
        while (!sr.EndOfStream)
        
            Countup++;
            if (Countup != Line)
            
                using (StringWriter sw = new StringWriter(sb))
                
                    sw.WriteLine(sr.ReadLine());
                
            
            else
            
                sr.ReadLine();
            
        
    
    using (StreamWriter sw = new StreamWriter(Path))
    
        sw.Write(sb.ToString());
    

【讨论】:

【参考方案6】:

我扩展了 Markus Olsson 的建议,并提出了这个添加多个搜索字符串和几个事件的类:

public static class TextLineRemover

    public static void RemoveTextLines(IList<string> linesToRemove, string filename, string tempFilename)
    
        // Initial values
        int lineNumber = 0;
        int linesRemoved = 0;
        DateTime startTime = DateTime.Now;

        // Read file
        using (var sr = new StreamReader(filename))
        
            // Write new file
            using (var sw = new StreamWriter(tempFilename))
            
                // Read lines
                string line;
                while ((line = sr.ReadLine()) != null)
                
                    lineNumber++;
                    // Look for text to remove
                    if (!ContainsString(line, linesToRemove))
                    
                        // Keep lines that does not match
                        sw.WriteLine(line);
                    
                    else
                    
                        // Ignore lines that DO match
                        linesRemoved++;
                        InvokeOnRemovedLine(new RemovedLineArgs  RemovedLine = line, RemovedLineNumber = lineNumber);
                    
                
            
        
        // Delete original file
        File.Delete(filename);

        // ... and put the temp file in its place.
        File.Move(tempFilename, filename);

        // Final calculations
        DateTime endTime = DateTime.Now;
        InvokeOnFinished(new FinishedArgs LinesRemoved = linesRemoved, TotalLines = lineNumber, TotalTime = endTime.Subtract(startTime));
    

    private static bool ContainsString(string line, IEnumerable<string> linesToRemove)
    
        foreach (var lineToRemove in linesToRemove)
        
            if(line.Contains(lineToRemove))
                return true;
        
        return false;
    

    public static event RemovedLine OnRemovedLine;
    public static event Finished OnFinished;

    public static void InvokeOnFinished(FinishedArgs args)
    
        Finished handler = OnFinished;
        if (handler != null) handler(null, args);
    

    public static void InvokeOnRemovedLine(RemovedLineArgs args)
    
        RemovedLine handler = OnRemovedLine;
        if (handler != null) handler(null, args);
    


public delegate void Finished(object sender, FinishedArgs args);

public class FinishedArgs

    public int TotalLines  get; set; 
    public int LinesRemoved  get; set; 
    public TimeSpan TotalTime  get; set; 


public delegate void RemovedLine(object sender, RemovedLineArgs args);

public class RemovedLineArgs

    public string RemovedLine  get; set; 
    public int RemovedLineNumber  get; set; 

用法:

TextLineRemover.OnRemovedLine += (o, removedLineArgs) => Console.WriteLine(string.Format("Removed \"0\" at line 1", removedLineArgs.RemovedLine, removedLineArgs.RemovedLineNumber));
TextLineRemover.OnFinished += (o, finishedArgs) => Console.WriteLine(string.Format("0 of 1 lines removed. Time used: 2", finishedArgs.LinesRemoved, finishedArgs.TotalLines, finishedArgs.TotalTime.ToString()));
TextLineRemover.RemoveTextLines(new List<string>  "aaa", "bbb" , fileName, fileName + ".tmp");

【讨论】:

【参考方案7】:

为什么不能用这个? 首先,创建一个数组:

string[] lines = File.ReadAllLines(openFileDialog1.FileName);

然后查找需要删除的行,用“”代替:

lines[x].Replace(lines[x], "");

完成!

【讨论】:

这不会从文件中删除行,它所做的只是使行x为空。因此,如果你经常这样做,你最终会在文件中得到一堆空返回,这可能会弄乱索引。 它实际上并没有取代任何东西。 string.Replace 是一个纯方法!【参考方案8】:

对于 非常 个大文件,我会做这样的事情

string tempFile = Path.GetTempFileName();

using(var sr = new StreamReader("file.txt"))
using(var sw = new StreamWriter(tempFile))

    string line;

    while((line = sr.ReadLine()) != null)
    
         if(line != "removeme")
             sw.WriteLine(line);
    


File.Delete("file.txt");
File.Move(tempFile, "file.txt");

更新我最初在 2009 年写了这篇文章,我认为更新可能会很有趣。今天你可以使用LINQ and deferred execution完成上述操作

var tempFile = Path.GetTempFileName();
var linesToKeep = File.ReadLines(fileName).Where(l => l != "removeme");

File.WriteAllLines(tempFile, linesToKeep);

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

上面的代码与第一个示例几乎完全相同,逐行读取,同时在内存中保留最少量的数据。

但可能需要免责声明。由于我们在这里讨论的是文本文件,因此您很少需要将磁盘用作中间存储介质。如果您不处理非常大的日志文件,那么将内容读入内存应该没有问题,并且不必处理临时文件。

File.WriteAllLines(fileName, 
    File.ReadLines(fileName).Where(l => l != "removeme").ToList());

请注意,.ToList 在此处对于强制立即执行至关重要。另请注意,所有示例都假定文本文件是 UTF-8 编码的。

【讨论】:

【参考方案9】:

我同意 John Saunders 的观​​点,这并不是 C# 特定的。但是,要回答您的问题:您基本上需要重写文件。有两种方法可以做到这一点。

将整个文件读入内存(例如使用File.ReadAllLines) 删除有问题的行(在这种情况下,将字符串数组转换为 List&lt;string&gt; 然后删除该行可能是最简单的) 写回所有其余的行(例如使用File.WriteAllLines) - 可能再次使用ToArrayList&lt;string&gt; 转换为字符串数组

这意味着你必须知道你有足够的内存。另一种选择:

打开输入文件和新的输出文件(作为TextReader/TextWriter,例如File.OpenTextFile.CreateText) 读取一行 (TextReader.ReadLine) - 如果您不想删除它,请将其写入输出文件 (TextWriter.WriteLine) 读完所有行后,关闭阅读器和编写器(如果您同时使用using 语句,这将自动发生) 如果要将输入替换为输出,请删除输入文件,然后将输出文件移动到位。

【讨论】:

我处于同样的情况,我必须删除文件的标题并将其附加到另一个文件中。在 Windows 上,如果我通过 C# 使用 DOS 函数,你认为这会提高性能吗?这是命令.. > MORE +1 "sourcefilepath" > "targetFilePath" @ImranAmjad:我不知道,但听起来并不难测试。这是您工作流程中对性能特别重要的部分吗? 是的,文件大小可能超过半 GB,我必须经常这样做。从 DOS 命令执行它会承担所有负担,我只确定它会更快,因为 dos 命令绕过所有操作系统层。我不确定很多内部结构。它还节省了很多代码行,但代码可读性对某些人来说是妥协的。 @ImranAmjad:半场演出听起来并不长。与其确定,不如试试?保存代码听起来是件好事,但如果速度对您来说那么重要,那么至少值得一试。 每个文件是半 GB 我将许多这样的文件附加到一个巨大的文件中。我试过了,它就像一个魅力。尚未完成基准测试。【参考方案10】:

我很简单:

打开文件进行读/写 阅读/搜索直到您要删除的行的开头 将写指针设置为当前读指针 通读到我们要删除的行的末尾并跳过换行符分隔符(计算字符数,我们称之为 nline) 逐字节读取并将每个字节写入文件 完成后将文件截断为 (orig_length - nline)。

【讨论】:

【参考方案11】:

读取文件,删除内存中的行并将内容放回文件(覆盖)。如果文件很大,您可能希望逐行读取它,并创建一个临时文件,然后替换原始文件。

【讨论】:

以上是关于如何从 C# 中的文本文件中删除一行?的主要内容,如果未能解决你的问题,请参考以下文章

从文本文件中读取一行,然后用新文本 C# 替换同一行

从pyspark中的文本文件中删除第一行和最后一行

C# 如何在文本文件中添加数据而不清除原来的内容?

在java中如何修改文本文件中的某一行的某些数据??

如何从文本文件中删除换行符?

如何从 IFS 下载文本文件的最后一行删除 CRLF