Cómo buscar y reemplazar texto en un archivo con C #

157

Mi código hasta ahora

StreamReader reading = File.OpenText("test.txt");
string str;
while ((str = reading.ReadLine())!=null)
{
      if (str.Contains("some text"))
      {
          StreamWriter write = new StreamWriter("test.txt");
      }
}

Sé cómo encontrar el texto, pero no tengo idea de cómo reemplazar el texto en el archivo con el mío.

Win Coder
fuente
Considere este comentario solo como un consejo: si tiene Visual Studio, puede incluir las carpetas en la solución y usar la función de búsqueda y reemplazo de Visual Studio
Mejor
Posible duplicado de Abrir un archivo y reemplazar cadenas en C #
RecklessSergio

Respuestas:

322

Leer todo el contenido del archivo. Haz un reemplazo con String.Replace. Escribir contenido de nuevo al archivo.

string text = File.ReadAllText("test.txt");
text = text.Replace("some text", "new value");
File.WriteAllText("test.txt", text);
Sergey Berezovskiy
fuente
55
@WinCoder BTW para reemplazos más complejos que puede usarRegex.Replace
Sergey Berezovskiy
35
Esto lee todo el archivo en la memoria a la vez, no siempre tan bien.
Banshee
66
@Banshee Touche 'Intenté leer 9,000,000 filas y me arrojaron una System out of memoryexcepción.
Squ1rr3lz
44
Para archivos grandes es un problema más complejo. Leer un fragmento de byte, analizarlos, leer otro fragmento, etc.
Alexander
66
@Alexander Right. Un fragmento termina con "... som", y el siguiente comienza con "e text ...". Lo convierte en un problema mucho más complicado.
djv
36

Te será difícil escribir en el mismo archivo del que estás leyendo. Una forma rápida es simplemente hacer esto:

File.WriteAllText("test.txt", File.ReadAllText("test.txt").Replace("some text","some other text"));

Puedes exponerlo mejor con

string str = File.ReadAllText("test.txt");
str = str.Replace("some text","some other text");
File.WriteAllText("test.txt", str);
Flynn1179
fuente
3
Esto es simple pero no deseable para archivos muy grandes. (PD: Yo no soy el que votó en contra)
Alvin Wong
3
Estoy de acuerdo, pero no puedes escribir en el archivo mientras estás leyendo. A menos que escriba en un archivo diferente, luego reemplácelo con un cambio de nombre después. De cualquier manera, el nuevo archivo debe almacenarse en otro lugar mientras lo construye, ya sea en la memoria o en el disco.
Flynn1179
@ Flynn1179 No es cierto en este ejemplo. Funciona. Pruébalo. Supongo que ReadAllTextcierra el acceso a los archivos antes de WriteAllText. Utilizo esta misma técnica en mi propia aplicación.
SteveCinq
Lo sé; este ejemplo no escribe mientras está leyendo, ¡ese era mi punto!
Flynn1179
27

Debe escribir todas las líneas que lee en el archivo de salida, incluso si no las cambia.

Algo como:

using (var input = File.OpenText("input.txt"))
using (var output = new StreamWriter("output.txt")) {
  string line;
  while (null != (line = input.ReadLine())) {
     // optionally modify line.
     output.WriteLine(line);
  }
}

Si desea realizar esta operación en su lugar, la forma más fácil es utilizar un archivo de salida temporal y, al final, reemplazar el archivo de entrada con la salida.

File.Delete("input.txt");
File.Move("output.txt", "input.txt");

(Intentar realizar operaciones de actualización en el medio del archivo de texto es bastante difícil de hacer porque siempre es difícil tener el reemplazo de la misma longitud, dado que la mayoría de las codificaciones son de ancho variable).

EDITAR: en lugar de dos operaciones de archivo para reemplazar el archivo original, mejor usar File.Replace("input.txt", "output.txt", null). (Ver MSDN ).

Ricardo
fuente
1
VB tuvo que cambiar 2 líneas: Uso de entrada como nuevo StreamReader (nombre de archivo) Mientras entrada.Peek ()> = 0
Brent
8

Es probable que tenga que extraer el archivo de texto en la memoria y luego hacer los reemplazos. Luego tendrá que sobrescribir el archivo utilizando el método que conoce claramente. Entonces, primero deberías:

// Read lines from source file.
string[] arr = File.ReadAllLines(file);

A continuación, puede recorrer y reemplazar el texto en la matriz.

var writer = new StreamWriter(GetFileName(baseFolder, prefix, num));
for (int i = 0; i < arr.Length; i++)
{
    string line = arr[i];
    line.Replace("match", "new value");
    writer.WriteLine(line);
}

Este método le da cierto control sobre las manipulaciones que puede hacer. O simplemente puede hacer el reemplazo en una línea

File.WriteAllText("test.txt", text.Replace("match", "new value"));

Espero que esto ayude.

Caballero de la Luna
fuente
6

Así es como lo hice con un archivo grande (50 GB):

Intenté 2 formas diferentes: la primera, leer el archivo en la memoria y usar Regex Reemplazar o Cadena Reemplazar. Luego agregué toda la cadena a un archivo temporal.

El primer método funciona bien para algunos reemplazos de Regex, pero Regex.Replace o String.Replace podrían causar un error de falta de memoria si realiza muchos reemplazos en un archivo grande.

El segundo es leer el archivo temporal línea por línea y construir manualmente cada línea usando StringBuilder y agregar cada línea procesada al archivo de resultados. Este método fue bastante rápido.

static void ProcessLargeFile()
{
        if (File.Exists(outFileName)) File.Delete(outFileName);

        string text = File.ReadAllText(inputFileName, Encoding.UTF8);

        // EX 1 This opens entire file in memory and uses Replace and Regex Replace --> might cause out of memory error

        text = text.Replace("</text>", "");

        text = Regex.Replace(text, @"\<ref.*?\</ref\>", "");

        File.WriteAllText(outFileName, text);




        // EX 2 This reads file line by line 

        if (File.Exists(outFileName)) File.Delete(outFileName);

        using (var sw = new StreamWriter(outFileName))      
        using (var fs = File.OpenRead(inFileName))
        using (var sr = new StreamReader(fs, Encoding.UTF8)) //use UTF8 encoding or whatever encoding your file uses
        {
            string line, newLine;

            while ((line = sr.ReadLine()) != null)
            {
              //note: call your own replace function or use String.Replace here 
              newLine = Util.ReplaceDoubleBrackets(line);

              sw.WriteLine(newLine);
            }
        }
    }

    public static string ReplaceDoubleBrackets(string str)
    {
        //note: this replaces the first occurrence of a word delimited by [[ ]]

        //replace [[ with your own delimiter
        if (str.IndexOf("[[") < 0)
            return str;

        StringBuilder sb = new StringBuilder();

        //this part gets the string to replace, put this in a loop if more than one occurrence  per line.
        int posStart = str.IndexOf("[[");
        int posEnd = str.IndexOf("]]");
        int length = posEnd - posStart;


        // ... code to replace with newstr


        sb.Append(newstr);

        return sb.ToString();
    }
vive el amor
fuente
0

Este código funcionó para mí

- //-------------------------------------------------------------------
                           // Create an instance of the Printer
                           IPrinter printer = new Printer();

                           //----------------------------------------------------------------------------
                           String path = @"" + file_browse_path.Text;
                         //  using (StreamReader sr = File.OpenText(path))

                           using (StreamReader sr = new System.IO.StreamReader(path))
                           {

                              string fileLocMove="";
                              string newpath = Path.GetDirectoryName(path);
                               fileLocMove = newpath + "\\" + "new.prn";



                                  string text = File.ReadAllText(path);
                                  text= text.Replace("<REF>", reference_code.Text);
                                  text=   text.Replace("<ORANGE>", orange_name.Text);
                                  text=   text.Replace("<SIZE>", size_name.Text);
                                  text=   text.Replace("<INVOICE>", invoiceName.Text);
                                  text=   text.Replace("<BINQTY>", binQty.Text);
                                  text = text.Replace("<DATED>", dateName.Text);

                                       File.WriteAllText(fileLocMove, text);



                               // Print the file
                               printer.PrintRawFile("Godex G500", fileLocMove, "n");
                              // File.WriteAllText("C:\\Users\\Gunjan\\Desktop\\new.prn", s);
                           }
poder radhason
fuente
0

tiendo a usar el código de reenvío simple tanto como puedo, el siguiente código funcionó bien

using System;
using System.IO;
using System.Text.RegularExpressions;

/// <summary>
/// Replaces text in a file.
/// </summary>
/// <param name="filePath">Path of the text file.</param>
/// <param name="searchText">Text to search for.</param>
/// <param name="replaceText">Text to replace the search text.</param>
static public void ReplaceInFile( string filePath, string searchText, string replaceText )
{
    StreamReader reader = new StreamReader( filePath );
    string content = reader.ReadToEnd();
    reader.Close();

    content = Regex.Replace( content, searchText, replaceText );

    StreamWriter writer = new StreamWriter( filePath );
    writer.Write( content );
    writer.Close();
}
Ali
fuente