How to delete a line from a text file in C#?
Asked Answered
B

11

64

I have a problem: how can I delete a line from a text file in C#?

Birdseed answered 21/3, 2009 at 7:19 Comment(1)
He/she means how to delete it programmatically I guess.Trudietrudnak
E
35

Read the file, remove the line in memory and put the contents back to the file (overwriting). If the file is large you might want to read it line for line, and creating a temp file, later replacing the original one.

Eichhorn answered 21/3, 2009 at 7:24 Comment(0)
Z
111

For very large files I'd do something like this

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");

Update I originally wrote this back in 2009 and I thought it might be interesting with an update. Today you could accomplish the above using 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);

The code above is almost exactly the same as the first example, reading line by line and while keeping a minimal amount of data in memory.

A disclaimer might be in order though. Since we're talking about text files here you'd very rarely have to use the disk as an intermediate storage medium. If you're not dealing with very large log files there should be no problem reading the contents into memory instead and avoid having to deal with the temporary file.

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

Note that The .ToList is crucial here to force immediate execution. Also note that all the examples assume the text files are UTF-8 encoded.

Zoarah answered 21/3, 2009 at 7:29 Comment(0)
E
35

Read the file, remove the line in memory and put the contents back to the file (overwriting). If the file is large you might want to read it line for line, and creating a temp file, later replacing the original one.

Eichhorn answered 21/3, 2009 at 7:24 Comment(0)
W
21

I agree with John Saunders, this isn't really C# specific. However, to answer your question: you basically need to rewrite the file. There are two ways you can do this.

  • Read the whole file into memory (e.g. with File.ReadAllLines)
  • Remove the offending line (in this case it's probably easiest to convert the string array into a List<string> then remove the line)
  • Write all the rest of the lines back (e.g. with File.WriteAllLines) - potentially convert the List<string> into a string array again using ToArray

That means you have to know that you've got enough memory though. An alternative:

  • Open both the input file and a new output file (as a TextReader/TextWriter, e.g. with File.OpenText and File.CreateText)
  • Read a line (TextReader.ReadLine) - if you don't want to delete it, write it to the output file (TextWriter.WriteLine)
  • When you've read all the lines, close both the reader and the writer (if you use using statements for both, this will happen automatically)
  • If you want to replace the input with the output, delete the input file and then move the output file into place.
Wolf answered 21/3, 2009 at 7:26 Comment(5)
I'm in same situation where I've to remove header of a file and append it into another file. On Windows, if I use DOS functions through C#, do you think it'd be a performance gain? Here is the command.. > MORE +1 "sourcefilepath" > "targetFilePath"Peel
@ImranAmjad: I don't know, but it doesn't sound like it would be hard to test. Is this a particularly performance-critical part of your workflow?Wolf
Yes, file size can be more than half a GB and I have to do it frequently. Doing it from DOS commands takes all the burden and I'm only sure that it's more faster as dos commands bypass all OS layers. I'm not sure about much of internals. It's also saves lots of lines of code as well but code readability is compromised to some ppl.Peel
@ImranAmjad: Half a gig doesn't really sound that long. Rather than being sure, why not try it? Saving code sounds like a good thing, but if speed is that important to you, surely it's at least worth trying.Wolf
Each file is half a GB an I'm appending many such files into one giant file. I've tried and it works like a charm. Haven't done bench marking yet.Peel
P
13

To remove an item from a text file, first move all the text to a list and remove whichever item you want. Then write the text stored in the list into a text file:

List<string> quotelist=File.ReadAllLines(filename).ToList();
string firstItem= quotelist[0];
quotelist.RemoveAt(0);
File.WriteAllLines(filename, quotelist.ToArray());
return firstItem;
Pastypat answered 29/5, 2012 at 9:42 Comment(4)
How about for "the other half" (okay, the other 0.05 percent) who don't have ReadAllLines() or WriteAllLines() in their version of .NET?Eupatrid
This really worked for me exactly how I wanted. Thank you for sharing this.Serin
List<string> quotelist = new List<string>(File.ReadAllLines(filename));Abnormality
File.WriteAllLines(filename, quotelist.ToArray());Abnormality
M
8

I extended what Markus Olsson suggested, and came up with this class that adds multiple search strings and a couple of event:

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; }
}

Usage:

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");
Mesonephros answered 14/4, 2011 at 15:6 Comment(0)
H
4

I wrote a method to delete lines from files.

This program uses using System.IO.

See my code:

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());
    }
}
Haemolysin answered 19/3, 2015 at 16:2 Comment(0)
J
3

I'd very simply:

  • Open the file for read/write
  • Read/seek through it until the start of the line you want to delete
  • Set the write pointer to the current read pointer
  • Read through to the end of the line we're deleting and skip the newline delimiters (counting the number of characters as we go, we'll call it nline)
  • Read byte-by-byte and write each byte to the file
  • When finished truncate the file to (orig_length - nline).
Jampan answered 21/3, 2009 at 8:17 Comment(0)
E
2

I realize it's been a long time, however this helped me so I wanted to improve on it. The answer from Leonhard was very useful for me. However, If your Text file is really huge like mine, StringBuilder will give an Out-Of-Memory Error. So instead I used it like this. Creates a new file and writes in it. You can then delete the first file if you like. Notice that Line variable determines until which line the file will be deleted. You can modify it to specify the interval of lines you want to delete.

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();
        }
    }
}
Eyeopener answered 31/8, 2021 at 14:55 Comment(0)
G
1
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);
}
Geriatrics answered 11/10, 2020 at 1:49 Comment(0)
L
0

Remove a block of code from multiple files

To expand on @Markus Olsson's answer, I needed to remove a block of code from multiple files. I had problems with Swedish characters in a core project, so I needed to install System.Text.CodePagesEncodingProvider nuget package and use System.Text.Encoding.GetEncoding(1252) instead of 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();
    }
Lighthouse answered 16/11, 2019 at 15:14 Comment(0)
B
-1

Why can't use this? First, create an array:

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

Then look up the line you need to delete and replace it with "" :

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

Done!

Bench answered 31/5, 2015 at 21:9 Comment(2)
This doesn't remove the line from the file, all it does is make line x empty. Therefore if you were doing this a lot, you would just end up with a bunch of empty returns in the file, which could mess up the indexes.Calvaria
It actually doesn't replace anything at all. string.Replace is a pure method!Geraldo

© 2022 - 2024 — McMap. All rights reserved.