Ver Mensaje Individual
  #2 (permalink)  
Antiguo 29/07/2003, 09:59
leonardop
 
Fecha de Ingreso: julio-2003
Mensajes: 165
Antigüedad: 20 años, 9 meses
Puntos: 1
Hola,

Es interesante el problema que describes, aunque me temo que no existe una solución trivial que cumpla con los requisitos que buscas (que no deba leerse el archivo entero o volcarlo).

La solución más natural es quizás usar un archivo temporal para almacenar allí el contenido actualizado del archivo y luego reemplazar el archivo original con el recién generado. Claro está que ese tipo de solución requiere precisamente leer por completo el contenido del archivo original (para volcarlo en el temporal):

Código:
<?php

// "Elemento" que se desea buscar
$item = '{E3:Sin micro:Sin memoria:Sin disco duro:CD-ROM:Negro}';

// Nuevo valor que se piensa guardar en el archivo (nos referimos al
// segundo elemento de una linea separada por comas)
$nuevo_valor = 2;


// Nombres de los archivos sobre los que se opera
$nombre_archivo = 'carrito.txt';  // Archivo con los datos originales
$nombre_tmp     = 'temp.txt';     // Nombre para un archivo temporal


// Nota: recuerde asegurarse de establecer los permisos adecuados para
// los archivos y directorios involucrados (si trabaja sobre un
// sistema operativo en el que los permisos tienen sentido)

$archivo = fopen ($nombre_archivo, 'r');
$tmp     = fopen ($nombre_tmp, 'w');


// Leer el archivo, linea por linea (considerando lineas de maximo 4kb
// de longitud)

while ($linea = fgets ($archivo, 4096)) {
    // Se asume que el separador de lexemas es la coma (`,')
    $lexemas = explode (',', $linea);

    if ($lexemas[0] == $item) {
        fwrite ($tmp, $lexemas[0] . ',' . $nuevo_valor . ',' . $lexemas[2]);
    } else
        fwrite ($tmp, $linea);
}

fclose ($tmp);
fclose ($archivo);

rename ($nombre_tmp, $nombre_archivo);

?>

Ahora bien, es posible hacer un procesamiento más eficiente si el contenido del archivo está organizado en bloques de tamaños fijos (lo que, como ocurre frecuentemente en otros lenguajes de programación, se podría conocer como "archivo de registros secuenciales"). En tal caso podría ser suficiente con seguir un algoritmo de este estilo:

a) Abrir el archivo de datos para lectura/escritura.
b) (mientras no se haya llegado al fin del archivo) Leer un bloque de N bytes del archivo.
c) Revisar si el bloque que se acaba de leer es el que queremos actualizar.
d) Si es así, actualizar el registro, y terminar el procesamiento del archivo. Cerrar el archivo.
e) De lo contrario, volver al paso b).

Una implementación en PHP podría ser algo como:

Código:
<?php

// "Elemento" que se desea buscar
$item = '{E3:Sin micro:Sin memoria:Sin disco duro:CD-ROM:Negro}';

// Nuevo valor que se piensa guardar en el archivo (nos referimos al
// segundo elemento de una linea separada por comas)
$nuevo_valor = 2;


$nombre_archivo = 'carrito.txt';  // Nombre del archivo con los datos
                                  // originales


$archivo = fopen ($nombre_archivo, 'r+');


// Leer el archivo, linea por linea (considerando lineas de maximo 4kb
// de longitud). Importante! Aqui asumimos que las lineas se van a
// conservar del mismo tamanyo, sin importar los datos que actualicemos.

$pos = 0;  // Posicion del apuntador en el archivo

while ($linea = fgets ($archivo, 4096)) {
    // Se asume que el separador de lexemas es la coma (`,')
    $lexemas = explode (',', $linea);

    if ($lexemas[0] == $item) {
        fseek ($archivo, $pos, SEEK_SET);
        fwrite ($archivo, $lexemas[0] . ',' .
                $nuevo_valor . ',' . $lexemas[2]);

        break;  // Si solo se espera encontrar una ocurrencia de
                // $item, se puede salir del ciclo inmediatamente
    }

    $pos = ftell ($archivo);
}

fclose ($archivo);

?>
Espero que te sea útil en la construcción de tu programa.

Un cordial saludo