Jue Feb 23, 2006 3:42 pm
|
 |
creating021
Vive para Perl en Español

|
Registrado: 23 Feb 2006
Mensajes: 486
Ubicación: Frente al monitor
|
|
| usando while y length |
|
|
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? |
|
|
|
Jue Feb 23, 2006 11:21 pm
|
 |
kidd
Creador de Perl en Español

|
Registrado: 15 Oct 2003
Mensajes: 1389
Ubicación: México
|
|
|
|
|
Hola:
Pon el código que estás usando ahorita para que podamos ayudarte con algunos tips para optimizarlo.
SALUDOS |
|
Vie Feb 24, 2006 5:28 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4128
Ubicación: Valladolid, España
|
|
|
|
|
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_ |
|
|

Vie Feb 24, 2006 2:09 pm
|
 |
creating021
Vive para Perl en Español

|
Registrado: 23 Feb 2006
Mensajes: 486
Ubicación: Frente al monitor
|
|
|
|
|
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  |
|

Vie Feb 24, 2006 3:47 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4128
Ubicación: Valladolid, España
|
|
|
|
|
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. |
|

Vie Feb 24, 2006 4:51 pm
|
 |
creating021
Vive para Perl en Español

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

|
Registrado: 23 Feb 2006
Mensajes: 486
Ubicación: Frente al monitor
|
|
|
|
|
En efecto 1.8G en 3 partes = 20m41.851s
Gracias  |
|
Powered by phpBB © 2001, 2005 phpBB Group
|