Modifier une ligne spécifique d'un fichier texte en C#

j'ai deux fichiers texte Source.txt et cible.txt. La source ne sera jamais modifiée et contiendra N Lignes de texte. Donc, je veux supprimer une ligne de texte spécifique dans la Cible.txt, et remplacer par une ligne de texte spécifique à partir de la Source.txt, je sais de quelle ligne j'ai besoin, en fait c'est la ligne numéro 2, les deux fichiers.

je n'ai quelque chose comme ceci:

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

Mais quand j'ouvre L'auteur, le fichier cible est effacé, il écrit les lignes, mais, quand il est ouvert, la cible le fichier ne contient que les lignes copiées, le reste est perdu.

Que puis-je faire?

22
demandé sur John Odom 2009-12-28 22:07:10

5 réponses

vous ne pouvez pas réécrire une ligne sans réécrire tout le fichier (à moins que les lignes ne soient de la même longueur). Si vos fichiers sont petits alors la lecture de tout fichier cible dans la mémoire et l'écriture de nouveau. Vous pouvez le faire comme ceci:

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

si vos fichiers sont volumineux, il serait préférable de créer un nouveau fichier pour que vous puissiez lire le streaming d'un fichier pendant que vous écrivez à l'autre. Cela signifie que vous n'avez pas besoin d'avoir tout le fichier en mémoire à lorsque. Vous pouvez le faire comme ceci:

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

vous pouvez ensuite déplacer le fichier une fois que vous êtes sûr que l'opération d'écriture a réussi (aucune excécution n'a été lancée et l'auteur est fermé).

notez que dans les deux cas, il est un peu déroutant que vous utilisiez l'indexation basée sur 1 pour vos numéros de ligne. Il pourrait être plus logique dans votre code d'utiliser l'indexation basée sur 0. Vous pouvez avoir un index basé sur 1 dans votre interface utilisateur à votre programme si vous le souhaitez, mais le convertir à un 0-indexé avant de l'envoyer plus loin.

de plus, un inconvénient d'écraser directement l'ancien fichier avec le nouveau fichier est que s'il échoue à mi-chemin, alors vous pourriez perdre de façon permanente toutes les données qui n'ont pas été écrites. En écrivant à un troisième fichier d'abord vous supprimez seulement les données originales après que vous êtes sûr que vous avez une autre copie (corrigée) de celui-ci, de sorte que vous pouvez récupérer les données si l'ordinateur plante à mi-chemin.

Une dernière remarque: j'ai remarqué que vos fichiers xml extension. Vous pourriez vouloir considérer s'il est plus logique pour vous d'utiliser un analyseur XML pour modifier le contenu des fichiers au lieu de remplacer des lignes spécifiques.

40
répondu Mark Byers 2012-08-22 02:44:52

la façon la plus facile est :

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

utilisation :

lineChanger("new content for this line" , "sample.text" , 34);
26
répondu Bruce Afruz 2016-04-08 08:19:42

quand vous créez un StreamWriter il crée toujours un fichier à partir de zéro, vous devrez créer un troisième fichier et copier à partir de la cible et remplacer ce dont vous avez besoin, puis remplacer l'ancien. Mais comme je peux voir ce que vous avez besoin est la manipulation XML, vous pourriez vouloir utiliser XmlDocument et modifiez votre fichier en utilisant Xpath.

3
répondu Pablo Retyk 2011-04-14 23:32:12

Vous devez Ouvrir le fichier de sortie pour l'accès en écriture plutôt que d'utiliser un nouveau StreamReader, qui écrase toujours le fichier de sortie.

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

bien sûr, vous devrez toujours chercher la bonne ligne dans le fichier de sortie, ce qui sera difficile car vous ne pouvez pas lire à partir de celui-ci, donc à moins que vous ne connaissiez déjà le byte offset à chercher, vous voulez probablement vraiment lire/écrire l'accès.

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

avec ce flux, vous pouvez lire jusqu'à ce que vous atteignez le point où vous voulez faites des changements, puis écrivez. Gardez à l'esprit que vous écrivez octets, et non pas des lignes, afin de remplacer une ligne, vous devez écrire le même nombre de caractères que la ligne que vous voulez modifier.

2
répondu John Knoeller 2009-12-28 19:43:15

je suppose que le dessous devrait fonctionner (au lieu de la partie écrivain de votre exemple). Je suis malheureusement sans environnement de construction donc il est de mémoire mais j'espère qu'il aide

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++;
            }
        }
2
répondu Rune FS 2009-12-28 20:25:54