• Publicidad

Usando while y length

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

Usando while y length

Notapor creating021 » 2006-02-23 16:42 @737

Hola.

He hecho un programa que corta archivos según un tamaño dado, pero el problema es que lo almacena en un '@' y lo trabaja por líneas, esto es muy lento y pesado, además pone la máquina muy lenta si el archivo es de 1 GB o más.

Así que supongo que si se pudiera trabajar con un while() (sacando del archivo cierto tamaño) sería más rápido.

La pregunta es: ¿cómo lo hago más rápido?
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

Publicidad

Notapor kidd » 2006-02-24 00:21 @056

Hola.

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


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

Re: usando while y length

Notapor explorer » 2006-02-24 06:28 @311

Si lo único que quieres es trocear 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: Seleccionar todo
split -a 3 -d -b 100k fichero_gordo.dat ficherito_
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 creating021 » 2006-02-24 15:09 @673

Sí, este es el código
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/boot/home/config/bin/perl -w
  2. use strict;
  3. my ( $do, $file, @out ) = @ARGV;
  4. die "Error, bad usage" unless @ARGV > 2;
  5.  
  6. sub cut {
  7.     open FL, $file or die "Error $file: $!";
  8.     my @line = <FL>;
  9.     close FL;
  10.     my $a = 0;
  11.     my $lines;
  12.     foreach (@line) { $lines = "$lines$line[$a++]"; }
  13.     my $allb = length $lines;
  14.     my $tama = $allb / $#out;
  15.     my $b    = 0;
  16.     my $d    = $tama;
  17.     my $e    = 0;
  18.     foreach (@out) {
  19.         if ( $d > $allb ) { die "Done\n"; }
  20.         open OT, "+>$out[$b]";
  21.         my $ot = substr( $lines, $e, $d );
  22.         print OT $ot;
  23.         close OT;
  24.         $b++;
  25.         $e = $e + $d;
  26.         $d = $d + $d;
  27.     }
  28.     die "Done\n";
  29. }
  30.  
  31. sub forme {
  32.     my $res;
  33.     my $x = 0;
  34.     my $a = 0;
  35.     foreach (@out) {
  36.         open A, $out[$a] or warn "Error $file: $!";
  37.         my @a = <A>;
  38.         my $z = 0;
  39.         foreach (@a) { $res = "$res$a[$z++]"; }
  40.         close A;
  41.         $a++;
  42.     }
  43.     open F, "+>$file" or die "Error $file: $!";
  44.     print F $res;
  45.     close F;
  46.     die "Done\n";
  47. }
  48. if ( $do eq "cut" )  { cut(); }
  49. if ( $do eq "make" ) { forme(); }
  50. die "Error: bad usage";
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4

Nota: La dirección #!/boot/home/config/bin/perl -w es para BeOS/Zeta, la idea es hacerlo 100% en Perl

Gracias :wink:
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

Re: usando while y length

Notapor explorer » 2006-02-24 16:47 @741

Es que ese es el problema... Estás 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:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2.  
  3. use warnings;
  4. use strict;
  5.  
  6. die "Error de uso.\n"
  7.    ."\tcut  <fichero origen> <fichero(s) destino>\n"
  8.    ."\tmake <fichero destino> <fichero(s) origen>\n" unless @ARGV > 2;
  9.  
  10. # Leemos el programa
  11. my $programa = shift @ARGV;
  12.  
  13. ## Hay que cortar el fichero origen en tantas partes como los de destino
  14. if ( $programa eq 'cut' ) {
  15.  
  16.   my ($origen, @destinos) = @ARGV;
  17.  
  18.   ## Abrimos el fichero de origen. Lo hacemos aquí para asegurarnos de que existe
  19.   open(my $fh, '<', $origen) or die "ERROR: No pude abrir el fichero de origen: $!\n";
  20.   binmode $fh;
  21.  
  22.   ## Tamaño de cada bloque. Cuidado con los redondeos: no podemos copiar medio byte!
  23.   my $tamano = int( 0.5 + ( (-s $origen) / @destinos) );
  24.  
  25.   ## Informar
  26.   print "Cortando $origen de ", -s $origen, " en ", scalar @destinos, " ficheros, de tamaño $tamano bytes cada uno...\n";
  27.  
  28.   ## Bucle de copia para todos los destinos
  29.   for ( my $i=0; $i < @destinos; $i++ ) {
  30.  
  31.     print "\tParte ", $i+1, " -> $destinos[$i]";
  32.  
  33.     ## Abrimos el fichero destino correspondiente
  34.     open(my $hl, '>', $destinos[$i]) or die "ERROR: No puedo escribir en $destinos[$i]: $!\n";
  35.     binmode $hl;
  36.  
  37.     ## Nos posicionamos dentro del fichero, leemos el trozo
  38.     my $buffer;
  39.     seek $fh, $i * $tamano, 0;
  40.     read $fh, $buffer, $tamano;
  41.  
  42.     ## Escribimos en el destino
  43.     print $hl $buffer;
  44.  
  45.     ## Cerramos fichero
  46.     close $hl;
  47.     print "\n";
  48.   }
  49.   close $fh;
  50.  
  51. ## Hay que abrir los ficheros y meterlos en el destino
  52. } elsif ( $programa eq 'make' ) {
  53.  
  54.   my ($destino, @origenes) = @ARGV;
  55.  
  56.   print "Uniendo los ficheros @origenes en el fichero $destino...\n";
  57.  
  58.   ## Abrimos el destino
  59.   open(my $hl, '>', $destino) or die "ERROR: No pude escribir en $destino: $!\n";
  60.   binmode $hl;
  61.  
  62.   foreach my $origen ( @origenes ) {
  63.  
  64.     print "\tLeyendo $origen";
  65.  
  66.     ## Abrimos origen
  67.     open(my $fh, '<', $origen) or die "ERROR: No pude abrir el fichero $origen: $!\n";
  68.     binmode $fh;
  69.  
  70.     ## Leemos el fichero y lo guardamos
  71.     my $buffer;
  72.     read $fh, $buffer, -s $origen;
  73.     print $hl $buffer;
  74.  
  75.     ## Cerramos fichero
  76.     close $fh;
  77.     print "\n";
  78.   }
  79.  
  80.   close $hl;
  81. }
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
Esta solución sólo tiene en memoria cada vez un tamaño igual a la de una parte del fichero, no el total.
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 creating021 » 2006-02-24 17:51 @785

print "Mil Gracias explorer!!!\n"x1000;
print "Mil Gracias Kidd!!!\n"x1000;

:D
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 creating021 » 2006-02-25 10:03 @460

En efecto, 1.8 GB en tres partes = 20m41.851s

Gracias :P
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


Volver a Básico

¿Quién está conectado?

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