Подтвердить что ты не робот

Редактирование определенной строки текстового файла в С#

У меня есть два текстовых файла: 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:\source.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, целевой файл стирается, он записывает строки, но при открытии целевой файл содержит только скопированные строки, остальные теряются.

Что я могу сделать?

4b9b3361

Ответ 1

Вы не можете переписать строку без перезаписи всего файла (если строки не имеют одинаковой длины). Если ваши файлы малы, тогда чтение всего целевого файла в память и последующее его повторное использование могут иметь смысл. Вы можете сделать это вот так:

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-парсер для изменения содержимого файлов вместо замены определенных строк.

Ответ 2

Самый простой способ:

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

Ответ 3

Когда вы создаете StreamWriter, он всегда создает файл с нуля, вам нужно будет создать третий файл и скопировать из цели и заменить то, что вам нужно, а затем заменить старый. Но поскольку я вижу, что вам нужно, это манипуляция XML, вы можете использовать XmlDocument и изменить свой файл с помощью Xpath.

Ответ 4

Вам нужно открыть выходной файл для доступа к записи, а не использовать новый 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);

с этим потоком, вы можете прочитать, пока не дойдете до точки, где хотите внести изменения, а затем напишите. Имейте в виду, что вы пишете байты, а не строки, поэтому для перезаписи строки вам потребуется написать то же количество символов, что и строка, которую вы хотите изменить.

Ответ 5

Я думаю, что ниже будет работать (а не часть автора из вашего примера). У меня, к сожалению, нет среды сборки, поэтому она из памяти, но я надеюсь, что она поможет

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