Pregunta

Tengo un gran archivo donde tengo que insertar ciertos caracteres en una ubicación específica.¿Cuál es la forma más fácil de hacerlo en C# sin tener que reescribir todo el archivo de nuevo.

¿Fue útil?

Solución

Los sistemas de ficheros no admiten la "introducción de datos" en el medio de un archivo.Si usted realmente tiene una necesidad de un archivo que puede ser escrita en función de un criterio de tipo de camino, le sugiero que busque en el uso de una base de datos incrustada.

Es posible que desee echar un vistazo a SQLite o BerkeleyDB.

Por otra parte, usted podría estar trabajando con un archivo de texto o de un legado de archivo binario.En ese caso la única opción es volver a escribir el archivo, al menos desde el punto de inserción hasta el final.

Me gustaría ver el FileStream clase para hacer de e/S aleatorias en C#.

Otros consejos

Probablemente será necesario volver a escribir el archivo desde el punto de insertar los cambios al final.Usted podría ser el mejor siempre escrito al final del archivo y el uso de herramientas tales como ordenar y grep para obtener los datos en el orden deseado.Estoy asumiendo que usted está hablando acerca de un archivo de texto, no de un archivo binario.

No hay manera de insertar caracteres en un archivo sin necesidad de volver a escribir.Con C# se puede hacer con cualquier Secuencia de clases.Si los archivos son enormes, les recomendamos el uso de GNU Core Utils en el interior de código de C#.Ellos son los más rápidos.Yo utilizada para manejar archivos de texto muy grandes con el núcleo de la utils ( de tamaños de 4 gb, 8 gb o más, etc ).Los comandos de la cabeza, la cola, la división, la csplit, gato, shuf, triturar, uniq realmente de gran ayuda en la manipulación de texto.

Por ejemplo, si usted necesita para poner algo de caracteres en un archivo de 2 gb, puede utilizar split -b BYTECOUNT, poner el ouptut en un archivo, anexar el nuevo texto, y obtener el resto de los contenidos y agregar a ella.Esto se debe, supuestamente, ser más rápido que cualquier otro medio.

Espero que funcione.Darle una oportunidad.

Usted puede utilizar el acceso aleatorio a escribir a lugares específicos de un archivo, pero usted no será capaz de hacerlo en formato de texto, usted tendrá que trabajar con bytes directamente.

Si usted sabe la ubicación específica a la que desea escribir los nuevos datos, el uso de la BinaryWriter clase:

using (BinaryWriter bw = new BinaryWriter (File.Open (strFile, FileMode.Open)))
{
    string strNewData = "this is some new data";
    byte[] byteNewData = new byte[strNewData.Length];

    // copy contents of string to byte array
    for (var i = 0; i < strNewData.Length; i++)
    {
        byteNewData[i] = Convert.ToByte (strNewData[i]);
    }

    // write new data to file
    bw.Seek (15, SeekOrigin.Begin);  // seek to position 15
    bw.Write (byteNewData, 0, byteNewData.Length);
}

Usted puede tomar un vistazo a este proyecto:Ganar Inspector De Datos

Básicamente, el código es el siguiente:

// this.Stream is the stream in which you insert data

{

long position = this.Stream.Position;

long length = this.Stream.Length;

MemoryStream ms = new MemoryStream();

this.Stream.Position = 0;

DIUtils.CopyStream(this.Stream, ms, position, progressCallback);

ms.Write(data, 0, data.Length);

this.Stream.Position = position;

DIUtils.CopyStream(this.Stream, ms, this.Stream.Length - position, progressCallback);

this.Stream = ms;

}

#region Delegates

public delegate void ProgressCallback(long position, long total);

#endregion

DIUtils.cs

public static void CopyStream(Stream input, Stream output, long length, DataInspector.ProgressCallback callback)
{
    long totalsize = input.Length;
    long byteswritten = 0;
    const int size = 32768;
    byte[] buffer = new byte[size];
    int read;
    int readlen = length < size ? (int)length : size;
    while (length > 0 && (read = input.Read(buffer, 0, readlen)) > 0)
    {
        output.Write(buffer, 0, read);
        byteswritten += read;
        length -= read;
        readlen = length < size ? (int)length : size;
        if (callback != null)
            callback(byteswritten, totalsize);
    }
}

Dependiendo del alcance de su proyecto, usted puede decidir para insertar cada línea de texto con el archivo en un tabla discbased.Como una especie de tabla de base de datos, de esa manera usted puede insertar a una ubicación específica en un momento dado, y no tener que leer-en, modificar y dar salida a todo el archivo de texto cada vez.Esto es debido al hecho de que sus datos es "enorme" como usted dice.Usted todavía podría volver a crear el archivo, pero al menos crear una solución escalable de esta manera.

Puede ser "posible" dependiendo de cómo el sistema de archivos almacena los archivos para insertar rápidamente (es decir, añadir más) bytes en el medio.Si es remotamente posible que sólo puede ser factible hacerlo en un bloque completo en un tiempo, y sólo por hacer bien el bajo nivel de modificación del sistema de ficheros en sí mismo o mediante el uso de un sistema de ficheros de interfaz específica.

Los sistemas de ficheros no están generalmente diseñados para esta operación.Si usted necesita de forma rápida hacer inserciones usted realmente necesita más general de la base de datos.

Dependiendo de su aplicación en un terreno intermedio sería manojo su inserta juntos, por lo que sólo una reescritura de el archivo en lugar de veinte.

Usted siempre tendrá que reescribir el resto de bytes desde el punto de inserción.Si este punto se encuentra en 0, entonces usted va a reescribir el archivo completo.Si se trata de 10 bytes antes de que el último byte, entonces usted va a reescribir el pasado 10 bytes.

En cualquier caso, no hay ninguna función para apoyar directamente "insertar archivo".Pero el código siguiente puede hacerlo de manera precisa.

var sw = new Stopwatch();
var ab = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ";

// create
var fs = new FileStream(@"d:\test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 262144, FileOptions.None);
sw.Restart();
fs.Seek(0, SeekOrigin.Begin);
for (var i = 0; i < 40000000; i++) fs.Write(ASCIIEncoding.ASCII.GetBytes(ab), 0, ab.Length);
sw.Stop();
Console.WriteLine("{0} ms", sw.Elapsed.TotalMilliseconds);
fs.Dispose();

// insert
fs = new FileStream(@"d:\test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 262144, FileOptions.None);
sw.Restart();
byte[] b = new byte[262144];
long target = 10, offset = fs.Length - b.Length;
while (offset != 0)
{
    if (offset < 0)
    {
        offset = b.Length - target;
        b = new byte[offset];
    }
    fs.Position = offset; fs.Read(b, 0, b.Length);
    fs.Position = offset + target; fs.Write(b, 0, b.Length);
    offset -= b.Length;
}
fs.Position = target; fs.Write(ASCIIEncoding.ASCII.GetBytes(ab), 0, ab.Length);
sw.Stop();
Console.WriteLine("{0} ms", sw.Elapsed.TotalMilliseconds);

Para obtener un mejor rendimiento de e / s de archivos, jugar con "la magia de dos powered números", como en el código anterior.La creación del archivo utiliza un búfer de 262144 bytes (256 KB) que no ayuda en absoluto.El mismo tampón para la inserción hace el "rendimiento del trabajo" como usted puede ver por el Cronómetro resultados si se ejecuta el código.Un proyecto de prueba en mi PC, dieron los siguientes resultados:

13628.8 ms para la creación y 3597.0971 ms para la inserción.

Tenga en cuenta que el objetivo de bytes para la inserción es de 10, lo que significa que casi todo el archivo fue reescrito.

¿Por qué no poner un puntero al final del archivo (literalmente, cuatro bytes por encima de la actual tamaño del archivo) y, a continuación, en el final del archivo escriba la longitud de los datos insertados, y finalmente los datos que desea insertar en sí.Por ejemplo, si usted tiene una cadena en el medio del archivo, y desea insertar unos caracteres en el medio de la cadena, puede escribir un puntero al final del archivo a través de algunos de los cuatro caracteres en la cadena y, a continuación, escribir cuatro caracteres al final junto con los personajes que en primer lugar quería insertar.Todo sobre el orden de los datos.Por supuesto, usted puede hacer esto sólo si usted está escribiendo todo el archivo por ti mismo, me refiero a que usted no está utilizando otros codecs.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top