C #: Antecedente al comienzo de un archivo

¿Cuál es la mejor manera de agregar texto al comienzo de un archivo usando C #?

No pude encontrar una manera directa de hacer esto, pero se me ocurrió un par de soluciones alternativas.

  1. Abra un archivo nuevo, escriba el texto que quería agregar, añada el texto del archivo anterior al final del nuevo archivo.

  2. Como el texto que deseo agregar debe tener menos de 200 caracteres, pensé que podía agregar caracteres de espacio en blanco al principio del archivo y luego sobrescribir el espacio en blanco con el texto que quería agregar.

¿Alguien más se ha encontrado con este problema? De ser así, ¿qué hiciste?

Agregar al principio de un archivo (anteponer en lugar de anexar) generalmente no es una operación compatible. Tus opciones # 1 están bien. Si no puede escribir un archivo temporal, puede extraer todo el archivo en la memoria, preparar sus datos en la matriz de bytes y luego sobrescribirlos (esto solo es posible si sus archivos son pequeños y no es necesario). tener un grupo en la memoria a la vez porque anteponer la matriz no es necesariamente fácil sin una copia tampoco).

Esto funciona para mí, pero para archivos pequeños. Probablemente no sea una solución muy buena de lo contrario.

string currentContent = String.Empty; if (File.Exists(filePath)) { currentContent = File.ReadAllText(filePath); } File.WriteAllText(filePath, newContent + currentContent ); 

Creo que la mejor manera es crear un archivo temporal. Agregue su texto y luego lea el contenido del archivo original y añádalo al archivo temporal. Luego puede sobrescribir el original con el archivo temporal.

Debería poder hacer esto sin abrir un archivo nuevo. Use el siguiente método de archivo:

 public static FileStream Open( string path, FileMode mode, FileAccess access ) 

Asegurándose de especificar FileAccess.ReadWrite.

Usando el FileStream devuelto desde File.Open, lea todos los datos existentes en la memoria. A continuación, restablezca el puntero al comienzo del archivo, escriba sus datos nuevos y luego escriba los datos existentes.

(Si el archivo es grande y / o sospecha que usa demasiada memoria, puede hacerlo sin tener que leer todo el archivo en la memoria, pero implementarlo se deja como un ejercicio para el lector).

Sí, básicamente puedes usar algo como esto:

 public static void PrependString(string value, FileStream file) { var buffer = new byte[file.Length]; while (file.Read(buffer, 0, buffer.Length) != 0) { } if(!file.CanWrite) throw new ArgumentException("The specified file cannot be written.", "file"); file.Position = 0; var data = Encoding.Unicode.GetBytes(value); file.SetLength(buffer.Length + data.Length); file.Write(data, 0, data.Length); file.Write(buffer, 0, buffer.Length); } public static void Prepend(this FileStream file, string value) { PrependString(value, file); } 

Entonces

 using(var file = File.Open("yourtext.txt", FileMode.Open, FileAccess.ReadWrite)) { file.Prepend("Text you want to write."); } 

Aunque no es realmente efectivo en el caso de archivos enormes.

Use esta clase:

 public static class File2 { private static readonly Encoding _defaultEncoding = new UTF8Encoding(false, true); // encoding used in File.ReadAll*() private static object _bufferSizeLock = new Object(); private static int _bufferSize = 1024 * 1024; // 1mb public static int BufferSize { get { lock (_bufferSizeLock) { return _bufferSize; } } set { lock (_bufferSizeLock) { _bufferSize = value; } } } public static void PrependAllLines(string path, IEnumerable contents) { PrependAllLines(path, contents, _defaultEncoding); } public static void PrependAllLines(string path, IEnumerable contents, Encoding encoding) { var temp = Path.GetTempFileName(); File.WriteAllLines(temp, contents, encoding); AppendToTemp(path, temp, encoding); File.Replace(temp, path, null); } public static void PrependAllText(string path, string contents) { PrependAllText(path, contents, _defaultEncoding); } public static void PrependAllText(string path, string contents, Encoding encoding) { var temp = Path.GetTempFileName(); File.WriteAllText(temp, contents, encoding); AppendToTemp(path, temp, encoding); File.Replace(temp, path, null); } private static void AppendToTemp(string path, string temp, Encoding encoding) { var bufferSize = BufferSize; char[] buffer = new char[bufferSize]; using (var writer = new StreamWriter(temp, true, encoding)) { using (var reader = new StreamReader(path, encoding)) { int bytesRead; while ((bytesRead = reader.ReadBlock(buffer,0,bufferSize)) != 0) { writer.Write(buffer,0,bytesRead); } } } } } 

preceder

 private const string tempDirPath = @"c:\temp\log.log", tempDirNewPath = @"c:\temp\log.new"; StringBuilder sb = new StringBuilder(); ... File.WriteAllText(tempDirNewPath, sb.ToString()); File.AppendAllText(tempDirNewPath, File.ReadAllText(tempDirPath)); File.Delete(tempDirPath); File.Move(tempDirNewPath, tempDirPath); using (FileStream fs = File.OpenWrite(tempDirPath)) { //truncate to a reasonable length if (16384 < fs.Length) fs.SetLength(16384); fs.Close(); } 
 // The file we'll prepend to string filePath = path + "\\log.log"; // A temp file we'll write to string tempFilePath = path + "\\temp.log"; // 1) Write your prepended contents to a temp file. using (var writer = new StreamWriter(tempFilePath, false)) { // Write whatever you want to prepend writer.WriteLine("Hi"); } // 2) Use stream lib methods to append the original contents to the Temp // file. using (var oldFile = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read)) { using (var tempFile = new FileStream(tempFilePath, FileMode.Append, FileAccess.Write, FileShare.Read)) { oldFile.CopyTo(tempFile); } } // 3) Finally, dump the Temp file back to the original, keeping all its // original permissions etc. File.Replace(tempFilePath, filePath, null); 

Incluso si lo que está escribiendo es pequeño, el archivo Temp obtiene todo el archivo original adjunto antes de .Replace (), por lo que debe estar en el disco.

Tenga en cuenta que este código no es Thread-safe; si más de un hilo accede a este código, puede perder escrituras en el intercambio de archivos que se está llevando a cabo aquí. Dicho esto, también es bastante caro, por lo que querrá tener acceso a la puerta de todos modos: pasar escrituras a través de múltiples proveedores a un búfer, que periódicamente se vacía a través de este método de anteponer en un único hilo de consumidor.

El siguiente algoritmo puede resolver el problema bastante fácilmente, es más eficiente para cualquier tamaño de archivo, incluidos los archivos de texto muy grandes:

 string outPutFile = @"C:\Output.txt"; string result = "Some new string" + DateTime.Now.ToString() + Environment.NewLine; StringBuilder currentContent = new StringBuilder(); List rawList = File.ReadAllLines(outPutFile).ToList(); foreach (var item in rawList) { currentContent.Append(item + Environment.NewLine); } File.WriteAllText(outPutFile, result + currentContent.ToString()); 

usando dos flujos, puede hacerlo en su lugar, pero tenga en cuenta que esto seguirá girando sobre todo el archivo en cada adición

 using System; using System.IO; using System.Text; namespace FilePrepender { public class FilePrepender { private string file=null; public FilePrepender(string filePath) { file = filePath; } public void prependline(string line) { prepend(line + Environment.NewLine); } private void shiftSection(byte[] chunk,FileStream readStream,FileStream writeStream) { long initialOffsetRead = readStream.Position; long initialOffsetWrite= writeStream.Position; int offset = 0; int remaining = chunk.Length; do//ensure that the entire chunk length gets read and shifted { int read = readStream.Read(chunk, offset, remaining); offset += read; remaining -= read; } while (remaining > 0); writeStream.Write(chunk, 0, chunk.Length); writeStream.Seek(initialOffsetWrite, SeekOrigin.Begin); readStream.Seek(initialOffsetRead, SeekOrigin.Begin); } public void prepend(string text) { byte[] bytes = Encoding.Default.GetBytes(text); byte[] chunk = new byte[bytes.Length]; using (FileStream readStream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { using(FileStream writeStream = File.Open(file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite)) { readStream.Seek(0, SeekOrigin.End);//seek chunk.Length past the end of the file writeStream.Seek(chunk.Length, SeekOrigin.End);//which lets the loop run without special cases long size = readStream.Position; //while there's a whole chunks worth above the read head, shift the file contents down from the end while(readStream.Position - chunk.Length >= 0) { readStream.Seek(-chunk.Length, SeekOrigin.Current); writeStream.Seek(-chunk.Length, SeekOrigin.Current); shiftSection(chunk, readStream, writeStream); } //clean up the remaining shift for the bytes that don't fit in size%chunk.Length readStream.Seek(0, SeekOrigin.Begin); writeStream.Seek(Math.Min(size, chunk.Length), SeekOrigin.Begin); shiftSection(chunk, readStream, writeStream); //finally, write the text you want to prepend writeStream.Seek(0,SeekOrigin.Begin); writeStream.Write(bytes, 0, bytes.Length); } } } } } 

Pon el contenido del archivo en una cadena. Agregue los datos nuevos que desea agregar a la parte superior del archivo a esa cadena: string = newdata + string . A continuación, mueva la posición de búsqueda del archivo a 0 y escriba la cadena en el archivo.