繁体   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