Esto ocurre como un problema independiente del lenguaje de programación para mí.
Tengo un archivo con el contenido
aaabddd
Cuando quiero insertar C
detrás, b
entonces mi código debe reescribirse ddd
para obtener
aaabCddd
¿Por qué no puedo simplemente insertar C
en esta posición?
No puedo hacer esto en Java, Python, .... No puedo hacer esto en Linux, Windows, .... Estoy en lo cierto?
No entiendo por qué C
no se puede insertar simplemente sin las escrituras adicionales. ¿Alguien podría explicar por qué esto es así?
Respuestas:
Dado que la mayoría de los sistemas de archivos almacenan el contenido de los archivos en bloques individuales que no son necesariamente contiguos en el disco físico, pero están vinculados a través de estructuras de puntero, parece que dicho modo - "insertar" en lugar de "agregar" o "sobrescribir" - debería ser posible, y ciertamente podría hacerse más eficiente que lo que tenemos que hacer ahora: leer todo el contenido, editar la secuencia de bytes y volver a escribir todo el contenido.
Sin embargo, para bien o para mal, la semántica UNIX de los sistemas de archivos se diseñó siguiendo el paradigma "aproximado y simple" en la década de 1970: le permite hacer todo, pero no necesariamente de la manera más eficiente posible. Hoy en día es casi impensable introducir un nuevo modo de apertura de archivos en la capa del Sistema de archivos virtual y tener alguna esperanza de que los principales sistemas de archivos adopten soporte para ello. Este es un motivo favorito mío, pero desafortunadamente es poco probable que se resuelva pronto.
fuente
Teóricamente, podría implementar un archivo que permitiría este tipo de cosas. Sin embargo, para obtener la máxima flexibilidad, necesitaría almacenar un puntero al siguiente byte junto con cada byte en el archivo. Suponiendo un puntero de 64 bits, eso significaría que 8 de cada 9 bytes de su archivo estaría compuesto por punteros internos. Por lo tanto, se necesitarían 9000 bytes de espacio para almacenar 1000 bytes de datos reales. Leer el archivo también sería lento, ya que necesitaría leer cada byte, leer el puntero, seguir el puntero para leer el siguiente byte, etc., en lugar de leer bloques de datos grandes y contiguos del disco.
Obviamente, este tipo de enfoque no es práctico. Sin embargo, podría dividir el archivo en, por ejemplo, bloques de 32 kb. Eso haría que sea relativamente fácil agregar 32 kb de datos en cualquier límite de 32 kb en el archivo. No sería más fácil agregar un solo byte como el quinto byte del archivo. Sin embargo, si reserva algo de espacio libre en cada bloque, podría permitir que se realicen pequeñas adiciones de datos que solo afectarían los datos en ese bloque único. Tendría una penalización en términos de tamaño de archivo, por supuesto, pero potencialmente una razonable. Sin embargo, descubrir cuánto espacio reservar y cómo dividir bloques tiende a ser mucho más fácil para una aplicación en particular que para un sistema de propósito general; lo que funciona en un contexto puede ser muy malo en otro dependiendo del acceso al archivo y características de modificación.
De hecho, muchos sistemas que pasan mucho tiempo interactuando con archivos implementan algo como lo que describí anteriormente cuando implementan su abstracción de archivo particular. Las bases de datos, por ejemplo, generalmente implementarán algún concepto de un "bloque" como la unidad más pequeña de E / S con la que pueden trabajar y generalmente reservarán una cierta cantidad de espacio para el crecimiento futuro, de modo que actualizar una fila en una tabla solo afecte un bloque en el que se almacenan esos datos en lugar de reescribir todo el archivo. Diferentes bases de datos, por supuesto, tienen diferentes implementaciones con diferentes compensaciones.
fuente
El "problema" se reduce a cómo los archivos se escriben en el medio de almacenamiento byte a byte.
En su representación más básica, un archivo no es más que una serie de bytes escritos en el disco (también conocido como medio de almacenamiento). Entonces su cadena original se ve así:
Y desea insertar
C
en la posición 0x04. Eso requiere desplazar los bytes 4 - 6 hacia abajo un byte para que pueda insertar el nuevo valor. Si no lo hace, sobrescribirá el valor que actualmente está en 0x04, que no es lo que desea.Entonces, la razón por la que tiene que volver a escribir la cola del archivo después de insertar un nuevo valor es porque no hay espacio dentro del archivo para aceptar el valor insertado. De lo contrario, sobrescribiría lo que había allí.
Anexo 1 : Si desea reemplazar el valor de
b
con,C
entonces no necesita volver a escribir la cola de la cadena. Reemplazar un valor con un valor de tamaño similar no requiere una reescritura.La adición 2 : Si desea reemplazar la cadena
ab
con elC
entonces tendría necesidad de volver a escribir el resto del archivo que se ha creado un vacío en el archivo.Anexo 3 : Las construcciones de nivel de bloque fueron creadas para hacer más fácil el manejo de archivos grandes. En lugar de tener que encontrar 1 millón de espacio contiguo para su archivo, ahora solo necesita encontrar 1 millón de bloques disponibles para escribir en su lugar.
En teoría, podría construir un sistema de archivos que vincule byte a byte de forma similar a lo que proporcionan los bloques. Luego puede insertar un nuevo byte actualizando el | de punteros en el punto apropiado. Me arriesgaría a adivinar que el rendimiento en eso sería bastante pobre.
Como sugirió el Gran Maestro B , use una imagen de fichas de dominó apiladas para comprender visualmente cómo se representa el archivo.
No puede insertar otro dominó dentro de la línea de dominó sin hacer que todo se caiga. Tienes que crear el espacio para el nuevo dominó moviendo a los demás por la línea. Mover fichas de dominó por la línea equivale a volver a escribir la cola del archivo después del punto de inserción.
fuente
La inserción en un archivo no se implementa en la mayoría de los sistemas de archivos porque se considera una operación "costosa" (que consume mucho tiempo y espacio) con repercusiones "costosas" potencialmente a largo plazo y modos de falla adicionales.
Un sistema de archivos con semántica de inserción probablemente usaría shift & insert (potencialmente muy costoso cuando inserta al frente de un archivo grande, pero no tiene / tiene pocos efectos secundarios a largo plazo) o algún tipo de asignación de montón generalizada con tamaños de asignación de longitud variable ( rendimiento muy mal comportamiento en algunos casos [¡imagínense las caras interactivas de los usuarios si intentan guardar un archivo durante un GC para detener el mundo!]).
Si desea experimentar, puede crear fácilmente una abstracción de E / S de archivo en Java o Python que implemente la inserción. Si tiene éxito y tiene características de rendimiento de buen comportamiento, tiene la base para un excelente trabajo de investigación. Buena suerte.
fuente
La forma más eficiente de insertar un bloque de bytes en el medio de un archivo sería:
fuente
Primero debe leer todo después del punto de inserción, luego volver a escribirlo con el espacio que va a insertar. Luego puede escribir sus datos de "inserción" en el lugar correcto. Funcionamiento de rendimiento extremadamente pobre, por lo tanto, no es compatible de forma nativa
fuente
Cuando accede directamente a un archivo, está utilizando un nivel bajo que puede usarse para construir estructuras más sofisticadas. Considere crear una base de datos con sus datos que permita los tipos de acceso que necesita, incluida la inserción.
Sería menos costoso si solo necesita recorrer el archivo sin hacer accesos aleatorios a un desplazamiento específico. Si necesita acceso aleatorio por desplazamiento en el archivo, deberá actualizar el índice para todos los bytes más allá del punto de inserción.
En general, pagará al indexar las estructuras de datos, la memoria para almacenar el índice y los accesos adicionales al disco para actualizarlo.
fuente