簡體   English   中英

如何從 C# 中的文本文件中刪除一行?

[英]How to delete a line from a text file in C#?

我有一個問題:如何從 C# 的文本文件中刪除一行?

對於非常大的文件,我會做這樣的事情

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

上面的代碼與第一個示例幾乎完全相同,逐行讀取,同時在 memory 中保留最少量的數據。

但是,免責聲明可能是正確的。 由於我們在這里討論的是文本文件,因此您很少需要將磁盤用作中間存儲介質。 如果您不處理非常大的日志文件,則將內容讀入 memory 應該沒有問題,並且避免處理臨時文件。

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

請注意, .ToList在這里對於強制立即執行至關重要。 另請注意,所有示例都假定文本文件是 UTF-8 編碼的。

讀取文件,刪除 memory 中的行並將內容放回文件(覆蓋)。 如果文件很大,您可能希望逐行讀取它,並創建一個臨時文件,然后替換原始文件。

我同意 John Saunders 的觀點,這並不是 C# 特定的。 但是,要回答您的問題:您基本上需要重寫文件。 有兩種方法可以做到這一點。

  • 將整個文件讀入 memory (例如使用File.ReadAllLines
  • 刪除有問題的行(在這種情況下,將字符串數組轉換為List<string>然后刪除該行可能是最簡單的)
  • 寫回所有 rest 行(例如使用File.WriteAllLines ) - 可能使用ToArray再次將List<string>轉換為字符串數組

這意味着你必須知道你有足夠的 memory。 替代:

  • 打開輸入文件和新的 output 文件(作為TextReader / TextWriter ,例如使用File.OpenTextFile.CreateText
  • 讀取一行 ( TextReader.ReadLine ) - 如果您不想刪除它,請將其寫入 output 文件 ( TextWriter.WriteLine )
  • 當你讀完所有行時,關閉閱讀器和作者(如果你對兩者都使用using語句,這將自動發生)
  • 如果您想用 output 替換輸入,請刪除輸入文件,然后將 output 文件移動到位。

要從文本文件中刪除項目,首先將所有文本移動到列表中,然后刪除您想要的任何項目。 然后將存儲在列表中的文本寫入文本文件:

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

我擴展了 Markus Olsson 的建議,並提出了這個 class,它添加了多個搜索字符串和幾個事件:

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

我寫了一個從文件中刪除行的方法。

該程序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());
    }
}

我很簡單:

  • 打開文件進行讀/寫
  • 閱讀/查找它,直到您要刪除的行的開頭
  • 將寫指針設置為當前讀指針
  • 通讀到我們要刪除的行尾並跳過換行符分隔符(計算我們 go 的字符數,我們稱之為 nline)
  • 逐字節讀取並將每個字節寫入文件
  • 完成后將文件截斷為 (orig_length - nline)。

我意識到這已經很長時間了,但這對我有幫助,所以我想改進它。 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();
        }
    }
}
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);
}

從多個文件中刪除一段代碼

為了擴展@Markus Olsson 的答案,我需要從多個文件中刪除一段代碼。 我在核心項目中遇到瑞典字符問題,因此我需要安裝 System.Text.CodePagesEncodingProvider nuget package 並使用 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();
    }

為什么不能用這個? 首先,創建一個數組:

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

然后查找您需要刪除的行並用“”替換它:

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

完畢!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM