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


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


36
2018-03-21 07:19


起源


他/她的意思是如何以编程方式删除它我猜。 - splattne


答案:


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


24
2018-03-21 07:24





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

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和延迟执行

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编码的。


66
2018-03-21 07:29





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

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

这意味着你必须知道你已经有足够的内存了。替代:

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

18
2018-03-21 07:26



我处于相同的情况,我要删除文件的标题并将其附加到另一个文件中。在Windows上,如果我通过C#使用DOS功能,你认为它会带来性能提升吗?这是命令..> MORE +1“sourcefilepath”>“targetFilePath” - Imran Amjad
@ImranAmjad:我不知道,但听起来并不难以测试。这是您工作流程中特别重要的性能部分吗? - Jon Skeet
是的,文件大小可以超过一半GB,我必须经常这样做。从DOS命令执行它可以承担所有的负担,我只能确保它更快,因为dos命令绕过所有OS层。我不太确定内部的内容。它还可以节省大量代码,但代码可读性会受到某些人的影响。 - Imran Amjad
@ImranAmjad:半场演出听起来并不那么久。而不是确定,为什么不 尝试一下?保存代码听起来像是一件好事,但如果速度快 是 对你来说很重要,当然这至少值得一试。 - Jon Skeet
每个文件都是半GB,我将许多这样的文件附加到一个巨大的文件中。我尝试过,它就像一个魅力。尚未做过基准测试。 - Imran Amjad


我扩展了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");

6
2018-04-14 15:06





要从文本文件中删除项目,请先将所有文本移动到列表中,然后删除所需的项目。然后将列表中存储的文本写入文本文件

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

6
2018-05-29 09:42



对于那些在他们的.NET版本中没有ReadAllLines()或WriteAllLines()的“另一半”(好吧,其他0.05%)怎么样? - B. Clay Shannon


我很简单:

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

3
2018-03-21 08:17





大家好我写了一个从文件中删除行的方法。 本程序使用 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());
        }
    }

2
2018-03-19 16:02





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

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

然后查找需要删除的行并将其替换为“”:

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

完成!


1
2018-05-31 21:09



这没有 去掉 文件中的行,它所做的就是make line x 空。因此,如果你这么做,你最终会在文件中出现一堆空的返回,这可能会搞砸索引。 - carefulnow1
它实际上根本不会取代任何东西。 string.Replace是一个纯方法! - csauve