Perl en Español

  1. Home
  2. Tutoriales
  3. Foro
  4. Artículos
  5. Donativos
  6. Publicidad
 

usando while y length

 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Básico
Mensaje Jue Feb 23, 2006 3:42 pm
creating021
Vive para Perl en Español
Vive para Perl en Español
Registrado: 23 Feb 2006
Mensajes: 486
Ubicación: Frente al monitor
usando while y length Responder citando

Hola.
He hecho un programa que corta archivos segun un tamaño dado, pero el problema es que lo almasena en un @ y lo trbaja por lineas, esto es muy lento y pesado, ademas pone la maquina muy lenta si el archivo es de 1G o mas.
Asi que supogo que si se pudiera trabajar con un while (sacando del archivo sierto tamaño) seria mas rapido.
La pregunta es: Como lo hago mas rapido?
Mensaje Jue Feb 23, 2006 11:21 pm
kidd
Creador de Perl en Español
Creador de Perl en Español
Registrado: 15 Oct 2003
Mensajes: 1389
Ubicación: México
Responder citando

Hola:

Pon el código que estás usando ahorita para que podamos ayudarte con algunos tips para optimizarlo.


SALUDOS
Mensaje Vie Feb 24, 2006 5:28 am
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4128
Ubicación: Valladolid, España
Responder citando

Si lo único que quieres es trozear un fichero grande en partes más pequeñas, te aconsejo que no utilices el split del Perl, sino el split del GNU.
Código:
split -a 3 -d -b 100k fichero_gordo.dat ficherito_
Mensaje Vie Feb 24, 2006 2:09 pm
creating021
Vive para Perl en Español
Vive para Perl en Español
Registrado: 23 Feb 2006
Mensajes: 486
Ubicación: Frente al monitor
Responder citando

Si, este es el codigo
Código:
#!/boot/home/config/bin/perl -w
use strict;
my ($do, $file, @out) = @ARGV;
die "Error, bad usage" unless @ARGV > 2;
sub cut {
 open FL, $file or die "Error $file: $!";
 my @line = <FL>;
 close FL;
 my $a = 0;
 my $lines;
 foreach(@line){$lines = "$lines$line[$a++]";}
 my $allb = length $lines;
 my $tama = $allb / $#out;
 my $b = 0;
 my $d = $tama;
 my $e = 0;
 foreach(@out){
    if($d > $allb){die "Done\n";}
    open OT, "+>$out[$b]";
    my $ot = substr($lines, $e, $d);
    print OT $ot;
    close OT;
    $b++;
    $e = $e+$d;
    $d = $d+$d;
 }
 die "Done\n";
}
sub forme {
 my $res;
 my $x = 0;
 my $a = 0;
 foreach(@out){
    open A, $out[$a] or warn "Error $file: $!";
    my @a = <A>;
    my $z = 0;
    foreach(@a){$res = "$res$a[$z++]";}
    close A;
    $a++;
 }
 open F, "+>$file" or die "Error $file: $!";
 print F $res;
 close F;
 die "Done\n";
}
if($do eq "cut"){cut();}
if($do eq "make"){forme();}
die "Error: bad usage";

Nota: La direccion #!/boot/home/config/bin/perl -w es para BeOS/Zeta, la idea es hacerlo 100% en perl
Gracias Wink
Mensaje Vie Feb 24, 2006 3:47 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4128
Ubicación: Valladolid, España
Responder citando

Es que ese es el problema... estas utilizando operaciones de cadena de caracteres, que, cuando se trata de ficheros muy grandes, puede llegar a saturar la memoria.
Lo mejor es no leer los ficheros. Sólo la parte que nos interesa.
Una forma posible de hacerlo:
Código:
#!/usr/bin/perl

use warnings;
use strict;

die "Error de uso.\n"
   ."\tcut  <fichero origen> <fichero(s) destino>\n"
   ."\tmake <fichero destino> <fichero(s) origen>\n" unless @ARGV > 2;

# Leemos el programa
my $programa = shift @ARGV;

## Hay que cortar el fichero origen en tantas partes como los de destino
if ( $programa eq 'cut' ) {

  my ($origen, @destinos) = @ARGV;

  ## Abrimos el fichero de origen. Lo hacemos aquí para asegurarnos de que existe
  open(my $fh, '<', $origen) or die "ERROR: No pude abrir el fichero de origen: $!\n";
  binmode $fh;

  ## Tamaño de cada bloque. Cuidado con los redondeos: no podemos copiar medio byte!
  my $tamano = int( 0.5 + ( (-s $origen) / @destinos) );

  ## Informar
  print "Cortando $origen de ", -s $origen, " en ", scalar @destinos, " ficheros, de tamaño $tamano bytes cada uno...\n";

  ## Bucle de copia para todos los destinos
  for ( my $i=0; $i < @destinos; $i++ ) {

    print "\tParte ", $i+1, " -> $destinos[$i]";

    ## Abrimos el fichero destino correspondiente
    open(my $hl, '>', $destinos[$i]) or die "ERROR: No puedo escribir en $destinos[$i]: $!\n";
    binmode $hl;

    ## Nos posicionamos dentro del fichero, leemos el trozo
    my $buffer;
    seek $fh, $i * $tamano, 0;
    read $fh, $buffer, $tamano;

    ## Escribimos en el destino
    print $hl $buffer;

    ## Cerramos fichero
    close $hl;
    print "\n";
  }
  close $fh;

## Hay que abrir los ficheros y meterlos en el destino
} elsif ( $programa eq 'make' ) {

  my ($destino, @origenes) = @ARGV;

  print "Uniendo los ficheros @origenes en el fichero $destino...\n";

  ## Abrimos el destino
  open(my $hl, '>', $destino) or die "ERROR: No pude escribir en $destino: $!\n";
  binmode $hl;

  foreach my $origen ( @origenes ) {

    print "\tLeyendo $origen";

    ## Abrimos origen
    open(my $fh, '<', $origen) or die "ERROR: No pude abrir el fichero $origen: $!\n";
    binmode $fh;

    ## Leemos el fichero y lo guardamos
    my $buffer;
    read $fh, $buffer, -s $origen;
    print $hl $buffer;

    ## Cerramos fichero
    close $fh;
    print "\n";
  }

  close $hl;
}
Esta solución sólo tiene en memoria cada vez un tamaño igual a la de una parte del fichero, no el total.
Mensaje Vie Feb 24, 2006 4:51 pm
creating021
Vive para Perl en Español
Vive para Perl en Español
Registrado: 23 Feb 2006
Mensajes: 486
Ubicación: Frente al monitor
Responder citando

print "Mil Gracias explorer!!!\n"x1000;
print "Mil Gracias Kidd!!!\n"x1000;
Very Happy
Mensaje Sab Feb 25, 2006 9:03 am
creating021
Vive para Perl en Español
Vive para Perl en Español
Registrado: 23 Feb 2006
Mensajes: 486
Ubicación: Frente al monitor
Responder citando

En efecto 1.8G en 3 partes = 20m41.851s
Gracias Razz
Publicar nuevo tema   Responder al tema    Foros de discusión -> Básico Todas las horas son GMT - 6 Horas
Página 1 de 1



Powered by phpBB © 2001, 2005 phpBB Group