Hola.
Hoy vengo con una pregunta que quizá sea media peliaguda... admito que no la he pensado mucho, pero ahí va.
Estoy haciendo una prueba de concepto de algunas ideas para un proyecto en pendiente. Y por lo que estado averiguando sobre el tema, hay ciertas técnicas que pueden ayudar al momento de guardar mucha info de lo mismo. Y si pinta bien, quizá considere añadir esto para mi repertorio.
Trataré de explicarme.
Hagamos de cuenta que tengo cierta cantidad de data que va a ser "procesada" en bloques. Se puede ver a cada bloque como una lista de items. La información es relativamente sencilla, por ahora es sólo un identificador.
Entonces tendríamos algo como esto:
Bloque 1: data1, data2, ..., dataN
Bloque 2: data1, data2, ..., dataN
...
Bloque M: data1, data2, ..., dataN
En memoria tanto M como N son conocidos y ya está la estructura presente para usar.
Bueno, parece fácil. Basta con recorrer la estructura y empezar a meterlo.
Pero hay cosas que pueden aderezar esto, la data a almacenar puede que se repita y por tanto podría ser bastante útil aplicar RLE para reducir de peso el archivo. Es más, mis fuentes dicen que es lo más aconsejable.
Por si desconocen, RLE es un algoritmo bastante simple de "compresión". Lo que hace es almacenar la información en forma de pares <x,y> siendo x la cantidad de repetidos en la serie hasta encontrar un elemento diferente e y el valor correspondiente.
Entonces ya podría hacerse algo como esto:
Bloque 1: <cant1, data1><cant2, data2>...<cantx,datax>
Bloque 2: <cant1, data1><cant2, data2>...<cantx,datax>
...
Bloque M: <cant1, data1><cant2, data2>...<cantx,datax>
Siendo x una cantidad desconocida. Por diseño del algoritmo RLE cant1 + ... + cantx necesariamente debe ser N.
Justamente como la data puede "comprimirse" y que dicho archivo va a reutilizarse, cualquier cambio en la data va a alterar las cosas.
Por lo que estuve viendo, y entiendo para que la información no se "pise" entre cada bloque, lo que se suele hacer es reservar un espacio o tamaño para cada bloque, lo suficiente (al menos en lo mínimo) como para cubrir el peor escenario de RLE: que no haya secuencias de repetidos:
Bloque 1: <1, data1><1, data2>...<1, dataN>
Bloque 2: <1, data1><1, data2>...<1, dataN>
...
Bloque 1: <1, data1><1, data2>...<1, dataN>
En el mejor caso tendré:
Bloque 1: <cantN, data>
Bloque 2: <cantN, data>
...
Bloque M: <cantN, data>
Pero en la mayoría las cosas será diferente y variable:
Bloque 1: <cant1, data1><cant2, data2>...<cantx, datax>
Bloque 2: <cant1, data1><cant2, data2>
...
Bloque M: <cant1, data1><cant2, data2>...<canty, datay>
Entonces, como dije, se estila "reservar" espacio entre los bloques para que uno pueda expandirse y/o achicarse sin riesgos de pisar un bloque ajeno.
Visualmente, las cosas sería algo como:
Bloque 1: <cantN, data>------------------------------------------------------------------
Bloque 2: <cant1, data1><cant2, data2>...<cantx,datax>------------------------
...
Bloque M: <1, data1><1, data2>..................................................<1,dataN>
Siendo "..." información que no se ve por razones de simplicidad, y "---" la memoria reservada disponible.
Mi pregunta es, ¿Cómo se hace para trabajar así? Estaba pensando en que quizá se puede aplicar o aprovechar algo de lo que implementé para mi otro trabajo. Pero no he probado en tirar datos en "bloques".
Esto de "reservar" como que no cierra. ¿Hay que dar un tamaño concreto al archivo, digamos como calcular el peor escenario contando todos los bloques, y de ahí jugar con seek() para ubicarnos en cada bloque? ¿Es decir, mandar la estructura completa a guardar con "ceros"? Por ejemplo digamos que M=300, N=500. En total tenemos 300x500 x Size(Dato) = 150000 x Size(Dato). Digamos que el dato entra en un byte, cada bloque consta de 500 bytes.
Entonces, en la etapa inicial al momento de crear por primera vez el archivo, para "reservar" cualquier bloque ¿haría algo como esto?
for i := 1 to 500 do Datas[bloque, i] := 0; Archivo.WriteBuffer(Datas[Bloque], 500); // No he probado realmente si acepta como buffer que se le indique la fila
En última, lo que podría hacerse, es ir uno a uno:
DataClear := 0; for i := 1 to 500 do Archivo.WriteBuffer(DataClear, 1); end;
Lo que obviamente hay que evitar.
Mi pregunta son: ¿O es que hay una forma más simple, correcta, limpia, y directa, de decirle "Mirá, necesito que aquí me dejes X cantidad de bytes disponibles para cuando quiera usar"? Y no tener que tener "generarlo" poniendo ceros... Si la hay, ¿que hace, pone 0 o se vería un vacio en el archivo?
Otra muy buena ventaja de hacer esa "reserva" es que de forma natural es posible calcular donde comienza cada bloque por lo que con Seek() lo tenemos muy cómodo. Siguiendo con el ejemplo, el bloque 1 va del byte 1 al 500, el bloque 2 del 501 al 1000, etc.
¿Y en casos en que tras una reescritura al aplicar el RLE se detecte que hay menos pares, que se hace con esa "basura"? En principio se la podría ignorar. Después de todo no molesta en realidad.
Me gustaría explorar esto de la RLE, ya que se está pensando en mucha data... y si encima de esto uno le aplica 7ZIP... reduce mucho el resultado final.
¿Cómo le harían ustedes? ¿O que técnicas se pueden emplear cuando el archivo es cambiante? ¿Mandarían a reescribir todo cada vez?
Saludos,