Perl en Español

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

Dividir un archivo por líneas
Ir a página 1, 2  Siguiente
 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Intermedio
Mensaje Lun Dic 11, 2006 12:53 pm
nany
Perlero Nuevo
Perlero Nuevo
Registrado: 11 Dic 2006
Mensajes: 17
Dividir un archivo por líneas Responder citando

Hola
Ojalá puedan ayudarme.
Tenga una lista de archivos en un directorio y ya los leí uno por uno. ¿Cómo puedo hacer para que en caso de que pase de las tres mil líneas cree el archivo con tres mil y después cree el mismo archivo añadiendo el numero dos y con las líneas restantes? ¡¡¡¡¡¡¡Ayúdenme!!!!!!!
Mensaje Lun Dic 11, 2006 3:04 pm
monoswim
Vive para Perl en Español
Vive para Perl en Español
Registrado: 18 Nov 2003
Mensajes: 720
Ubicación: Buenos Aires
Responder citando

No te entendí mucho , pero es fácil...

¿ Sabés leer un archivo línea por línea ?
Perl:
open(FILE,'<fff.txt');
while(my $line = <FILE>){

}
close FILE;
#PARA CONTAR LAS LÍNEAS SIMPLEMENTE $i++;


¿ Sabés crear un nuevo archivo ? open(FILE,'>NEWFILE')

No creo que tengas mayores complicaciones... Hacer un condicional que evalúe el $i y ya...

Espero que te sirva

saludos
Mensaje Lun Dic 11, 2006 5:01 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4225
Ubicación: Valladolid, España
Responder citando

Supongamos que has metido todas las líneas en el array @lineas.
Si suponemos también que el fichero puede tener entre 1 y 6000 líneas, tenemos que dividir su contenido entre uno o dos ficheros.
Perl:
$fichero = "salida1";
@resto = splice( @lineas, 3_000 );
print "Salida en fichero 1 $fichero\n";
# Aquí grabamos las @lineas

++$fichero;
if ( @resto ) {
    print "Salida en fichero 2 $fichero\n";
    # Aquí grabamos el @resto
}

Darse cuenta de que ni siquiera comprobamos si tenemos 3000 líneas, más o menos... Perl nos ahorra MUCHO trabajo.
Mensaje Mar Dic 12, 2006 1:55 pm
creating021
Vive para Perl en Español
Vive para Perl en Español
Registrado: 23 Feb 2006
Mensajes: 498
Ubicación: Frente al monitor
Responder citando

http://perlenespanol.baboonsoftware.com/foro/viewtopic.php?p=3332&highlight=#3332
Laughing
Mensaje Lun Dic 18, 2006 1:34 pm
nany
Perlero Nuevo
Perlero Nuevo
Registrado: 11 Dic 2006
Mensajes: 17
respuestas Responder citando

hola, mil gracias por sus respuestas; me fueron muy útiles. ¡¡¡¡saludos!!!! Smile
Mensaje Lun Dic 18, 2006 1:43 pm
nany
Perlero Nuevo
Perlero Nuevo
Registrado: 11 Dic 2006
Mensajes: 17
Responder citando

Hola, podrían ayudarme por favor a revisar este código, ¡¡¡¡please!!!!
Perl:
################///Abrir Directorio
    opendir DIR, "$s_Dir" or die "ERR: Al leer directorio [ " . $s_Dir ."]\n";
    my @a_Archivos = readdir (DIR);
    close DIR;
###############///Abrir Archivo
sub leeArchivoArr{

    foreach my $s_NombreArchivo (@a_Archivos){
    my $s_Archivo = $s_Dir . "/" . $s_NombreArchivo;
    open IN, "$s_Archivo"  or die "ERR: Al abrir [ $s_Archivo ]\n";
     my $i_ContLineas = 0;
    while (<IN>) {
       $i_ContLineas++;
     }
    print "INF: Archivo [$s_Archivo] con [$i_ContLineas ] Lineas\n";
    close IN;
###############///comparacion
     while (scalar @a_Archivo >3000){

         my @a_arreglo3000 = splice @a_Archivo,3000;
         my $s_archivonuevo = "$home" + "$s_archivonuevo" + "$i_Contarchivo";

          open OUT ,">$s_archivonuevo";
          print OUT "$s_arreglo3000\n";
          close OUT;
          my $s_contArchivo = 0;
          $s_contArchivo ++;
          }

     if ($a_Archivo < 3000){
        my $s_archivonuevo = "$home" + "$s_archivonuevo" + "$i_Contarchivo";

          open OUT ,">$s_archivonuevo";
          print OUT "$a_Archivo";
           close OUT;
           }
}
Mensaje Lun Dic 18, 2006 4:18 pm
creating021
Vive para Perl en Español
Vive para Perl en Español
Registrado: 23 Feb 2006
Mensajes: 498
Ubicación: Frente al monitor
Responder citando

Perl:
#!/usr/bin/env perl
use strict;
use Cwd;

my $s_Dir = getcwd();
opendir DIR, "$s_Dir" or die "ERR: Al leer directorio [ " . $s_Dir ."]\n";
my @a_Archivos = readdir (DIR);
closedir DIR;

sub leerArchivoArr {
  foreach my $file (@a_Archivos){
    if(-f $file){ # si es un fichero...
      open IN, $file or die "Error: $_ $!\n";
      my $linea = 0;
      while(<IN>){
          $linea++;
      }
      close IN;
      print "INF: Archivo [$s_Dir/$file] con [$linea] Lineas\n";
    }
  }
}
leerArchivoArr();

Lo otro no se para que así que...
Mensaje Lun Dic 18, 2006 5:08 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4225
Ubicación: Valladolid, España
Responder citando

Hay varios errores:
* La variable $s_arreglo3000 no está inicializada en ningún sitio. Supongo que te refieres a la @a_arreglo3000.

* La línea de 'my $s_contArchivo = 0;' debería estar antes del while. De otra forma, ese contador siempre valdrá uno dentro del bucle e indefinido fuera de él.

* La variable $a_Archivo no está inicializada en ningún sitio. Supongo que te refieres a la @a_Archivo.

* ¿Qué ocurre si el número de líneas es exactamente múltiplo de 3000? Pues que el último if también se ejecuta y se crea un archivo nuevo de tamaño 0.
Mensaje Lun Dic 18, 2006 5:39 pm
creating021
Vive para Perl en Español
Vive para Perl en Español
Registrado: 23 Feb 2006
Mensajes: 498
Ubicación: Frente al monitor
Este... Responder citando

Perl:
my $s_archivonuevo = "$home" + "$s_archivonuevo" + "$i_Contarchivo";


  • Se declara dos veces
  • $home y $s_archivonuevo no son números ($Home no ha sido declarado y $_archivonuevo no se puede definir a si mismo).
    Intenta concatenar con coma (",") o punto (".") como esto:
    my$resultado = $variableuno, $variabledos;

Rolling Eyes

La función leeArchivoArr núnca es llamada así que $s_Archivo queda indefinido si alguna vez fue definido.

Lo mejor, scalar es más rápido que $#array + 1y dos segúndos más rapido que $scalar = @array; Cool yo no lo sabía.
Mensaje Lun Dic 18, 2006 5:45 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4225
Ubicación: Valladolid, España
Responder citando

La coma no sirve para concatenar strings.
Mensaje Lun Dic 18, 2006 6:07 pm
creating021
Vive para Perl en Español
Vive para Perl en Español
Registrado: 23 Feb 2006
Mensajes: 498
Ubicación: Frente al monitor
Responder citando

explorer escribió:
La coma no sirve para concatenar strings.

Embarassed cierto, que pena de verdad, no sirve.
Mensaje Mar Dic 19, 2006 10:51 am
nany
Perlero Nuevo
Perlero Nuevo
Registrado: 11 Dic 2006
Mensajes: 17
Responder citando

gracias por sus respuestas la verdad me ha costado un poco de trabajo este lenguaje saludos!!!!!
Mensaje Mar Dic 19, 2006 11:20 am
Perl user
Maestro Honorario
Maestro Honorario
Registrado: 03 Nov 2004
Mensajes: 385
Responder citando

explorer escribió:
Supongamos que has metido todas las líneas en el array @lineas.
Si suponemos también que el fichero puede tener entre 1 y 6000 líneas, tenemos que dividir su contenido entre uno o dos ficheros.
Perl:
$fichero = "salida1";
@resto = splice( @lineas, 3_000 );
print "Salida en fichero 1 $fichero\n";
# Aquí grabamos las @lineas

++$fichero;
if ( @resto ) {
    print "Salida en fichero 2 $fichero\n";
    # Aquí grabamos el @resto
}

Darse cuenta de que ni siquiera comprobamos si tenemos 3000 líneas, más o menos... Perl nos ahorra MUCHO trabajo.


No reinventemos el hilo negro, ya está hecho.

Tie::File hace estas tareas demasiado sencillas y triviales, como para evitarnos el uso de splice y lectura directa. Recordemos que Tie::File incluso tiene caching y otras monerías muy útiles.

Échenle un vistazo al módulo, no por algo está dentro de los Core modules de Perl.

Saludos.
Mensaje Mar Dic 19, 2006 2:11 pm
nany
Perlero Nuevo
Perlero Nuevo
Registrado: 11 Dic 2006
Mensajes: 17
Responder citando

Hola a todos. Bueno, el leer línea por línea ya me queda claro pero aún no he podido generar que de un archivo de supongamos 8500 líneas que se llama juanito me derive tres archivos uno con juanito1 con las primeras 3000 líneas, juanito2 con las siguientes 3000 líneas y juanito3 con las restantes. Este es mi código que aunque según ya no tiene errores no hace lo que pido. Ayuda.

Perl:
/Abrir Directorio
    opendir DIR, "$s_Dir" or die "ERR: Al leer directorio [ " . $s_Dir ."]\n";
    my @a_Archivos = readdir (DIR);
    close DIR;
###############///Abrir Archivo
sub leeArchivoArr{

    foreach my $s_NombreArchivo (@a_Archivos){
    my $s_Archivo = $s_Dir . "/" . $s_NombreArchivo;
    open IN, "$s_Archivo"  or die "ERR: Al abrir [ $s_Archivo ]\n";
     my $i_ContLineas = 0;
     my @a_Archivo = <IN>;
    print "INF: Archivo [$s_Archivo] con [$i_ContLineas ] Lineas\n";
    close IN;
###############///comparacion
       my $s_contArchivo1 = 0;
     while (scalar @a_Archivo >3000){

          my @a_arreglo3000 = splice (@a_Archivo,3000);
         my $s_archivonuevo = $ENV{"HOME"}."$s_NombreArchivo"."$s_contArchivo1";

          open OUT ,">$s_archivonuevo";
          print OUT "$s_Archivo\n";
          close OUT;
          $s_contArchivo1 ++;
          }

     if (@a_Archivo < 3000){
        my $s_contArchivo = 0;
        my $s_archivonuevo = $ENV{"HOME"}."$s_NombreArchivo" . "$s_contArchivo";

          open OUT ,">$s_archivonuevo";
          print OUT "$s_Archivo";
           close OUT;
          $s_contArchivo ++;
           }
}
Mensaje Mar Dic 19, 2006 8:40 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4225
Ubicación: Valladolid, España
Responder citando

Hay algunos errores de lógica. Hay algunas variables que nunca se usan o nunca han sido inicializadas.

Lo primero que he hecho es crear unos ficheros de prueba con el comando
bash:
perl -le 'print "Linea ", ++$numero for 1..8500' > juanito

El siguiente programa busca en el subdirectorio 'ficheros' todos esos ficheros generados antes y los divide, dejándolos en el directorio raíz, como pones en tu programa.
Perl:
    1 #!/usr/bin/perl
    2
    3 use warnings;
    4 use strict;
    5
    6 my $s_Dir = 'ficheros';
    7
    8 ### Abrir Directorio
    9 opendir DIR, "$s_Dir" or die "ERR: Al leer directorio [ $s_Dir ]\n";
   10 my @a_Archivos = grep { -f "$s_Dir/$_" } readdir (DIR);
   11 close DIR;
   12
   13 ### Abrir Archivo
   14 foreach my $s_NombreArchivo ( @a_Archivos ) {
   15     my $s_Archivo = $s_Dir . "/" . $s_NombreArchivo;
   16     open IN, "$s_Archivo" or die "ERR: Al abrir [ $s_Archivo ]\n";
   17     my @a_Archivo = <IN>;
   18     print "INF: Archivo [$s_Archivo] con [", scalar @a_Archivo, "] Lineas\n";
   19     close IN;
   20
   21     ### Comparación
   22     my $s_contArchivo1  = 1;
   23     while ( @a_Archivo > 3000 ) {
   24         my @a_arreglo3000 = splice(@a_Archivo, 0, 3000);
   25         my $s_archivonuevo = $ENV{"HOME"}."/$s_NombreArchivo$s_contArchivo1";
   26
   27         print "INF: Archivo salida [$s_archivonuevo]\n";
   28         open OUT ,">$s_archivonuevo";;
   29         print OUT @a_arreglo3000;
   30         close OUT;
   31         $s_contArchivo1++;
   32     }
   33
   34     if (@a_Archivo <= 3000) {
   35         my $s_archivonuevo = $ENV{"HOME"}."/$s_NombreArchivo$s_contArchivo1";
   36
   37         print "INF: Archivo salida [$s_archivonuevo]\n";
   38         open OUT ,">$s_archivonuevo";
   39         print OUT @a_Archivo;
   40         close OUT;
   41         $s_contArchivo1++;
   42     }
   43 }
* En las líneas 3 y 4 activamos unos pragmas para que nos ayuden a programar bien
* En la décima vamos leyendo todos los ficheros del directorio, pero sólo nos quedamos con aquellos que sean realmente ficheros normales (-f)
* El bucle de la decimo cuarta y siguientes analiza todos esos ficheros. Por cada uno lo abrimos y lo leemos entero
* Luego comienza la división. Con el bucle while repetimos mientras tengamos más de tres mil líneas
* En la línea vigésimo cuarta obtenemos las primeras tres mil líneas
* Y las grabamos en la vigésimo novena
* En la trigésimo primera, incrementamos el contador sufijo del nombre de salida
* El if de las líneas trigésimo cuarta y siguientes hacen lo mismo con el resto del fichero. Realmente no es necesario este if porque sabemos que ahí el fichero siempre tiene menos de tres mil líneas

Una mejora en la lógica sería: vamos a partir un fichero mientras tengamos algo que partir:
Perl:
    1 #!/usr/bin/perl
    2
    3 use warnings;
    4 use strict;
    5
    6 my $s_Dir = 'ficheros';
    7
    8 # Abrir Directorio
    9 opendir DIR, "$s_Dir" or die "ERR: Al leer directorio [ $s_Dir ]\n";
   10 my @a_Archivos = grep { -f "$s_Dir/$_" } readdir (DIR);
   11 close DIR;
   12
   13 ### Abrir Archivo
   14 foreach my $s_NombreArchivo ( @a_Archivos ) {
   15     my $s_Archivo = $s_Dir . "/" . $s_NombreArchivo;
   16     open IN, "$s_Archivo" or die "ERR: Al abrir [ $s_Archivo ]\n";
   17     my @a_Archivo = <IN>;
   18     print "INF: Archivo [$s_Archivo] con [", scalar @a_Archivo, "] Lineas\n";
   19     close IN;
   20
   21     ### Comparación
   22     my $s_contador = 1;
   23     while ( @a_Archivo ) {
   24         my @a_arreglo3000 = splice(@a_Archivo, 0, 3000);
   25         my $s_salida = "$ENV{HOME}/$s_NombreArchivo$s_contador";
   26         print "INF: Archivo salida [$s_salida]\n";
   27         open OUT ,">$s_salida";
   28         print OUT @a_arreglo3000;
   29         close OUT;
   30         $s_contador++;
   31     }
   32 }
Los únicos cambios están en la parte de Comparación:
* En la línea 22 tenemos una variable contador que se encargará del sufijo
* La línea siguiente es la base de la lógica: mientras tengamos líneas qué repartir...
* ... sacamos 3000 de ellas con splice en la línea siguiente
* Las imprimimos, y listo.

Claro que... si estuvieras en Unix, este problema lo tendrías resuelto con el comando 'split':
bash:
split -l 3000 -a 1 -d juanito juanito
Publicar nuevo tema   Responder al tema    Foros de discusión -> Intermedio Todas las horas son GMT - 6 Horas
Ir a página 1, 2  Siguiente
Página 1 de 2



Powered by phpBB © 2001, 2005 phpBB Group