• Publicidad

Duda muy básica sobre ficheros

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Duda muy básica sobre ficheros

Notapor fgalves » 2007-08-17 07:25 @351

Hola a todos,

El caso es que tengo una duda muy básica sobre ficheros.

Tengo un fichero temporal (FILEOUT) que va aumentando en tamaño pues voy almacenando datos en él a partir de la información leída en FILEIN.

Cuando dicho fichero (FILEOUT) llega a un cierto número de lineas (7000 en el ejemplo más abajo), hago un volcado del contenido de dicho fichero a otro, y suprimo el contenido del mismo para empezar de cero, cerrando y abriendo el fichero con la opción '>'.

Lo que llevo hecho es lo siguiente:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
while (my $l = <FILEIN>) {
    print FILEOUT $l;
    $counter++;
    if ($counter == 7000)
    {
        `cat $workingDirectory/$flatTmpProjFileName >$workingDirectory/output_$numero.txt`;
        close(FILEOUT);
        open(FILEOUT,">$fileout");
        $counter = 0;
        $numero++;
Coloreado en 0.005 segundos, usando GeSHi 1.0.8.4


Es decir, cierro el fichero temporal (FILEOUT), y lo vuelvo a abrir con la opcion ">" de forma que sobrescriba el contenido anterior.
El caso es que funciona, pero me gustaría saber si existe otra forma más sencilla y quizás más eficiente de hacerlo.

¡Gracias por adelantado!
¡Saludos!
Felipe
fgalves
Perlero nuevo
Perlero nuevo
 
Mensajes: 210
Registrado: 2006-09-25 13:54 @621

Publicidad

Notapor explorer » 2007-08-17 08:13 @384

Es mejor que hagas antes el 'close' que el 'cat', porque así te aseguras que no pierdes contenido almacenado en el buffer de escritura.

Y si hay otra forma más sencilla... ahora no se me ocurre... quizás reescribir el código para convertir sus partes en subutinas y no tener que duplicar líneas.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor monoswim » 2007-08-17 08:14 @385

El tema es que estás haciendo un bucle de 7000 vueltas y eso es medio pesado...

Si usas esas comillas para hacer el 'cat', porque no la usas para hacer un 'cp' y luego con open '>' lo vacías... (fíjate que te falta el 'close' luego del open '>'...)

Y en vez de chequear que haya 7000 filas yo me fijaría por el peso del archivo... que lo calculas fácilmente con -s.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my $tamano = -s $archivo;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Espero que te sirva...

:adios:
MonoSwim
Perl Programming Language
Avatar de Usuario
monoswim
Perlero nuevo
Perlero nuevo
 
Mensajes: 452
Registrado: 2003-11-18 16:13 @717
Ubicación: Buenos Aires

Notapor kidd » 2007-08-17 08:17 @386

Hola,

Hay un módulo que se llama File::Split que te puede dividir un archivo en varios archivos de x líneas o menos, quizá te sirva darle un vistazo y a lo mejor te dá una idea para atacar el problema desde otro angúlo.

Saludos
Uriel Lizama Perl programmer fundador de Perl en Español
Perl Programming Language
Avatar de Usuario
kidd
Creador de Perl en Español
Creador de Perl en Español
 
Mensajes: 1166
Registrado: 2003-10-15 16:52 @744
Ubicación: México

Notapor explorer » 2007-08-17 08:20 @388

monoswim escribiste:El tema es que estás haciendo un bucle de 7000 vueltas y eso es medio pesado...
Es bastante menos pesado que consultar al sistema operativo para saber el tamaño del fichero.

monoswim escribiste:Si usas esas comillas para hacer el 'cat', porque no la usas para hacer un 'cp' y luego con open '>' lo vacías...
Sí, es mucho mejor hacer un 'cp' o un 'mv' que un 'cat'.

monoswim escribiste:(fíjate que te falta el 'close' luego del open '>'...)
Yo creo que no...
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor fgalves » 2007-08-17 08:57 @414

¡Gracias a todos por vuestros consejos!

De hecho, si no he entendido mal, File::Split sirve para, dado un fichero de entrada (un fichero "completo" en el sentido que contiene todos los datos a tratar), trocearlo en múltiples ficheros de salida, lo cual no es exactamente lo que deseo hacer.

En mi caso, mi fichero de entrada (FILEIN) NO es un fichero completo conteniendo TODOS los datos a tratar, sino que son pequeños ficheros (más de uno) que son generados cada 15 minutos. El contenido de dichos ficheros es añadido al fichero temporal del que hablé antes (FILEOUT), para luego ser eliminados. Por lo tanto, dicho fichero FILEOUT es un acumulativo de los datos obtenidos hasta el momento. Eso ya esta implementado.

Lo que intento hacer, es un "split" pero en tiempo real (para llamarlo de alguna manera). Es decir, cuando dicho fichero temporal alcanza un número de líneas determinado, vuelco su contenido a un fichero de salida, y luego vacío su contenido y pongo el contador a cero repitiendo dicha operación cuantas veces haga falta. Al final del día, mi objetivo es tener múltiples ficheros .txt en vez de un solo fichero temporal FILEOUT conteniendo la totalidad de los datos.

Espero no haberme enrollado demasiado, pero es que no me resulta fácil explicar el problema.
Gracias de todos modos. Pondré a prueba vuestras recomendaciones.

Por cierto Explorer: ¿Por qué es mucho mejor un cp que un cat? ¿Es quizás más eficiente?

Un cordial saludo,
Felipe
fgalves
Perlero nuevo
Perlero nuevo
 
Mensajes: 210
Registrado: 2006-09-25 13:54 @621

Notapor monoswim » 2007-08-17 11:24 @517

Es bastante menos pesado que consultar al sistema operativo para saber el tamaño del fichero.


wow :shock: !!! nunca me lo hubiese imaginado !!!

¿Y por qué no le falta el close? cuando abrís solo para vaciarlo ¿no hace falta cerrarlo?

Hoy aprendí 2 importantes lecciones :D :D

Saludos
PD: una pregunta, no puedes ir contando cada vez que le metes una línea al archivo, ¿cómo es la entrada de datos al archivo temporal?
MonoSwim
Perl Programming Language
Avatar de Usuario
monoswim
Perlero nuevo
Perlero nuevo
 
Mensajes: 452
Registrado: 2003-11-18 16:13 @717
Ubicación: Buenos Aires

Notapor Perl user » 2007-08-17 13:02 @584

explorer escribiste:Es bastante menos pesado que consultar al sistema operativo para saber el tamaño del fichero.


Qué tal explorer,

Estás en un error, es bastante MENOS pesado pedirle al SO que te indique el tamaño del archivo (hablamos del tamaño en bytes), ya que solo falta una llamada al sistema stat, el cual solo verifica el i-node del archivo que ya contiene una entrada con su tamaño actual en bytes, aparte de otros datos importantes.

Hacer una iteración de 7 mil elementos jamás será menos pesado que una simple llamada al sistema que NO realiza ningún calculo.

fgalves escribiste:Hola a todos,

El caso es que tengo una duda muy básica sobre ficheros.

Tengo un fichero temporal (FILEOUT) que va aumentando en tamaño pues voy almacenando datos en él a partir de la información leída en FILEIN.

Cuando dicho fichero (FILEOUT) llega a un cierto número de lineas (7000 en el ejemplo más abajo), hago un volcado del contenido de dicho fichero a otro, y suprimo el contenido del mismo para empezar de cero, cerrando y abriendo el fichero con la opción '>'.

Lo que llevo hecho es lo siguiente:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
while (my $l = <FILEIN>) {
    print FILEOUT $l;
    $counter++;
    if ($counter == 7000)
    {
        `cat $workingDirectory/$flatTmpProjFileName >$workingDirectory/output_$numero.txt`;
        close(FILEOUT);
        open(FILEOUT,">$fileout");
        $counter = 0;
        $numero++;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Es decir, cierro el fichero temporal (FILEOUT), y lo vuelvo a abrir con la opcion ">" de forma que sobrescriba el contenido anterior.
El caso es que funciona, pero me gustaría saber si existe otra forma más sencilla y quizás más eficiente de hacerlo.

¡Gracias por adelantado!
¡Saludos!
Felipe


Por otro lado, la solución que yo recomendaría para localizar la cantidad de líneas sería usando Tie::File, que sabe eficientemente como búscar cada línea y representarla en el array al que tiene amarrado, y simplemente verificar si existe el elemento 7 mil del arreglo, si así es, entonces ya puedes obtener dichos elementos. Después, ya podrías utilizar algún otro módulo para partir el archivo, o simplemente obtener la posición de la línea número 7 mil, y con un sysread copiar desde 0 hasta N bytes de la línea 7 mil al nuevo archivo.


Saludos,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

Notapor creating021 » 2007-08-17 17:05 @753

monoswim escribiste:Si usas esas comillas para hacer el 'cat', porque no la usas para hacer un 'cp' y luego con open '>' lo vacías... (fíjate que te falta el 'close' luego del open '>'...)

Pues no sé si sea mejor, pero podría usar read con un buffer de 1024 para lograrlo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
sub mv {
  my ($filein, $fileout) = @_; # seria bueno adaptarlo a IO::Handle
  local $| = 1;
  open FLIN, $filein;
  open FLOT, "+>$fileout";
  binmode(FLIN);
  binmode(FLOT);
  while(not eof(FLIN)){
     my $buf;
     read(FLIN, $buf, 1024);
     print FLOT $buf;
  }
  close FLIN;
  close FLOT;
  unlink $filein;
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

:mrgreen:
Expect the worst, is it the least you can do?
Avatar de Usuario
creating021
Perlero frecuente
Perlero frecuente
 
Mensajes: 595
Registrado: 2006-02-23 16:17 @720
Ubicación: Frente al monitor

Notapor explorer » 2007-08-17 18:33 @815

Perl user escribiste:
explorer escribiste:Es bastante menos pesado que consultar al sistema operativo para saber el tamaño del fichero.


Qué tal explorer,

Estás en un error, es bastante MENOS pesado pedirle al SO que te indique el tamaño del archivo (hablamos del tamaño en bytes), ya que solo falta una llamada al sistema stat, el cual solo verifica el i-node del archivo que ya contiene una entrada con su tamaño actual en bytes, aparte de otros datos importantes.

Hacer una iteración de 7 mil elementos jamás será menos pesado que una simple llamada al sistema que NO realiza ningún cálculo.

Precisamente... Si fgalves tiene que hacer un test para comprobar si tiene que recortar el fichero, yo he supuesto que ese test lo va a hacer al final de la escritura de cada línea... entonces... ¿aumentar un escalar y comprobar que ha llegado a 7000 es más costoso que una llamada a stat() y una comprobación? O dicho de otra manera, ya que hay que hacer una comprobación en cada línea, ¿aumentar un escalar es más costoso que una llamada a stat()?

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl

use strict;
use Benchmark qw(:all) ;

my $count = -1;
my $lineas = 0;

cmpthese( $count, {
    'escalar'   => sub { $lineas++ },
    'stat'      => sub { -s $0     },
});
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Código: Seleccionar todo
             Rate    stat escalar
stat     591644/s      --    -91%
escalar 6467594/s    993%      --


Otra cosa muy distinta es que sepamos que el fichero de entrada esté quieto y entonces queramos saber si tiene más de 7000 líneas o cuál es su tamaño. Entonces sí que sólo hay una llamada a stat() y tienes toda la razón, pero fgalves habla de "tiempo real" y yo he supuesto que el fichero va creciendo continuamente, por lo que hay que hacer comprobaciones continuas.

Nos falta un poquito más de detalle del problema para saber realmente lo que es más eficiente...
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Siguiente

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 3 invitados