簡體   English   中英

在 C# 中編輯文本文件的特定行

[英]Edit a specific Line of a Text File in C#

我有兩個文本文件,Source.txt 和 Target.txt。 源永遠不會被修改並包含 N 行文本。 所以,我想刪除 Target.txt 中的特定文本行,並用 Source.txt 中的特定文本行替換,我知道我需要多少行,實際上是第 2 行,兩個文件。

我有這樣的東西:

string line = string.Empty;
int line_number = 1;
int line_to_edit = 2;

using StreamReader reader = new StreamReader(@"C:\target.xml");
using StreamWriter writer = new StreamWriter(@"C:\target.xml");

while ((line = reader.ReadLine()) != null)
{
    if (line_number == line_to_edit)
        writer.WriteLine(line);

    line_number++;
}

但是當我打開 Writer 時,目標文件被擦除,它寫入行,但是,當打開時,目標文件只包含復制的行,其余的都丟失了。

我能做什么?

最簡單的方法是:

static void lineChanger(string newText, string fileName, int line_to_edit)
{
     string[] arrLine = File.ReadAllLines(fileName);
     arrLine[line_to_edit - 1] = newText;
     File.WriteAllLines(fileName, arrLine);
}

用法 :

lineChanger("new content for this line" , "sample.text" , 34);

您不能在不重寫整個文件的情況下重寫一行(除非這些行恰好具有相同的長度)。 如果您的文件很小,那么將整個目標文件讀入內存然后再次將其寫出可能是有意義的。 你可以這樣做:

using System;
using System.IO;

class Program
{
    static void Main(string[] args)
    {
        int line_to_edit = 2; // Warning: 1-based indexing!
        string sourceFile = "source.txt";
        string destinationFile = "target.txt";

        // Read the appropriate line from the file.
        string lineToWrite = null;
        using (StreamReader reader = new StreamReader(sourceFile))
        {
            for (int i = 1; i <= line_to_edit; ++i)
                lineToWrite = reader.ReadLine();
        }

        if (lineToWrite == null)
            throw new InvalidDataException("Line does not exist in " + sourceFile);

        // Read the old file.
        string[] lines = File.ReadAllLines(destinationFile);

        // Write the new file over the old file.
        using (StreamWriter writer = new StreamWriter(destinationFile))
        {
            for (int currentLine = 1; currentLine <= lines.Length; ++currentLine)
            {
                if (currentLine == line_to_edit)
                {
                    writer.WriteLine(lineToWrite);
                }
                else
                {
                    writer.WriteLine(lines[currentLine - 1]);
                }
            }
        }
    }
}

如果您的文件很大,最好創建一個新文件,以便您可以在寫入另一個文件時從一個文件讀取流。 這意味着您不需要一次將整個文件保存在內存中。 你可以這樣做:

using System;
using System.IO;

class Program
{
    static void Main(string[] args)
    {
        int line_to_edit = 2;
        string sourceFile = "source.txt";
        string destinationFile = "target.txt";
        string tempFile = "target2.txt";

        // Read the appropriate line from the file.
        string lineToWrite = null;
        using (StreamReader reader = new StreamReader(sourceFile))
        {
            for (int i = 1; i <= line_to_edit; ++i)
                lineToWrite = reader.ReadLine();
        }

        if (lineToWrite == null)
            throw new InvalidDataException("Line does not exist in " + sourceFile);

        // Read from the target file and write to a new file.
        int line_number = 1;
        string line = null;
        using (StreamReader reader = new StreamReader(destinationFile))
        using (StreamWriter writer = new StreamWriter(tempFile))
        {
            while ((line = reader.ReadLine()) != null)
            {
                if (line_number == line_to_edit)
                {
                    writer.WriteLine(lineToWrite);
                }
                else
                {
                    writer.WriteLine(line);
                }
                line_number++;
            }
        }

        // TODO: Delete the old file and replace it with the new file here.
    }
}

一旦您確定寫入操作成功(沒有拋出異常並且寫入器已關閉),您就可以隨后移動文件。

請注意,在這兩種情況下,您對行號使用基於 1 的索引都有些令人困惑。 在您的代碼中使用基於 0 的索引可能更有意義。 如果您願意,您可以在程序的用戶界面中使用基於 1 的索引,但在進一步發送之前將其轉換為 0 索引。

此外,用新文件直接覆蓋舊文件的缺點是,如果中途失敗,那么您可能會永久丟失未寫入的任何數據。 通過首先寫入第三個文件,您只有在確定您有另一個(更正)副本后才刪除原始數據,因此如果計算機中途崩潰,您可以恢復數據。

最后一句話:我注意到你的文件有一個 xml 擴展名。 您可能需要考慮使用 XML 解析器來修改文件的內容而不是替換特定行是否更有意義。

當您創建StreamWriter它總是從頭開始創建一個文件,您必須創建第三個文件並從目標復制並替換您需要的內容,然后替換舊的。 但正如我所看到的,您需要的是 XML 操作,您可能希望使用XmlDocument並使用 Xpath 修改您的文件。

我想下面應該工作(而不是你的例子中的作者部分)。 不幸的是,我沒有構建環境,所以它來自記憶,但我希望它有所幫助

using (var fs = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite)))
        {
            var destinationReader = StreamReader(fs);
            var writer = StreamWriter(fs);
            while ((line = reader.ReadLine()) != null)
            {
              if (line_number == line_to_edit)
                {
                    writer.WriteLine(lineToWrite);
                }
                else
                {
                    destinationReader .ReadLine();
                }
                line_number++;
            }
        }

您需要打開輸出文件以進行寫訪問,而不是使用新的 StreamReader,它總是會覆蓋輸出文件。

StreamWriter stm = null;
fi = new FileInfo(@"C:\target.xml");
if (fi.Exists)
   stm = fi.OpenWrite();

當然,您仍然必須在輸出文件中尋找正確的行,這將很難,因為您無法從中讀取,因此除非您已經知道要尋找的字節偏移量,否則您可能真的想要讀/寫使用權。

FileStream stm = fi.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);

使用此流,您可以閱讀直到到達要進行更改的點,然后再寫入。 請記住,您正在寫入字節,而不是行,因此要覆蓋一行,您需要寫入與要更改的行相同數量的字符。

好的,解決方案工作正常。 但是當相同的文本出現在多個地方時,我需要更改單行文本。 為此,需要定義一個trackText以在該文本之后開始查找,最后將oldText更改為newText

 private int FindLineNumber(string fileName, string trackText, string oldText, string newText)
    {
        int lineNumber = 0;
        string[] textLine = System.IO.File.ReadAllLines(fileName);
        for (int i = 0; i< textLine.Length;i++)
        {
            if (textLine[i].Contains(trackText)) //start finding matching text after.
                traced = true;
            if (traced)
                if (textLine[i].Contains(oldText)) // Match text
                {
                    textLine[i] = newText; // replace text with new one.
                    traced = false;
                    System.IO.File.WriteAllLines(fileName, textLine);
                    lineNumber = i;
                    break; //go out from loop
                }   
        }
        return lineNumber 
    }

希望對其他人有所幫助。

暫無
暫無

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

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