• Publicidad

Abrir archivo xls con Spreadsheet::WriteExcel

Aquí encontrarás todo lo que sea específicamente acerca de módulos de Perl. Ya sea que estás compartiendo tu módulo, un manual o simplemente tienes una duda acerca de alguno.

Abrir archivo xls con Spreadsheet::WriteExcel

Notapor silva » 2013-01-23 14:12 @633

Creo un archivo xls con el módulo Spreadsheet::WriteExcel. Puedo verlo y se crea bien. Mi problema es que quiero abrir ese archivo desde un cgi, y este no se abre.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl -w
  2.  
  3. use strict;
  4. use CGI ':all';
  5. use Spreadsheet::WriteExcel;
  6.  
  7. # Suponiendo creado OK el archivo prueba.xls, Luego:
  8.  
  9.    open (FILE, "/tmp/archivos_xls/prueba.xls");
  10.    local ($/);
  11.    my $file = <FILE>;
  12.    close (FILE);
  13.  
  14.     print "Content-type: application/vnd.ms-excel\n";
  15.     print "Content-Disposition: attachment; filename='prueba.xls'\n";
  16.     print "Content-Description: File to download\n\n";
  17.  
  18.     print $file;
  19.  
  20.  
  21.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


Al ejecutar el cgi, no abre el archivo aunque éste está creado. ¿Cómo hago para abrirlo? ¿Qué sintaxis utilizo? ¡¡¡¡Gracias!!!!
silva
Perlero nuevo
Perlero nuevo
 
Mensajes: 82
Registrado: 2011-05-24 05:59 @291

Publicidad

Re: Abrir archivo xls con Spreadsheet::WriteExcel

Notapor explorer » 2013-01-23 15:30 @687

A ver... la secuencia de acciones, más o menos, es:
  • tu llamas al cgi con el navegador web
  • el navegador pasa la petición al servidor web
  • el servidor web localiza el cgi y lo ejecuta
  • el cgi carga el módulo, busca el archivo, y lo envía por la salida estándar precedido por unas cabeceras
  • el servidor web encamina todo eso hacia el navegador web
  • tu navegador recibe todo, y al ver las cabeceras, se da cuenta de que es de un tipo de archivo que no conoce, así que se lo pasa al sistema operativo
  • el sistema operativo debe buscar en su base de datos qué aplicación debe arrancar para poder mostrar archivos ms-excel. Si no encuentra ninguno, responde con error
  • si encuentra alguna aplicación, la arranca y le pasa como argumento el nombre del archivo, que estará almacenado en la carpeta de archivos temporales, donde lo dejó el navegador web

Entonces...
  • en tu cgi no necesitas cargar el módulo Spreadsheet::WriteExcel, porque tu cgi no necesita escribir en ningún archivo Excel. Solo quieres transportarlo
  • la lectura de archivos binarios debe indicarse de modo explícito. Si no, Perl creará que estás leyendo un archivo de texto. En la línea 11, $file contendrá todo el archivo Excel prueba.xls, pero los bytes que hayan coincidido con alguna secuencia especial (como los caracteres de nueva línea) pueden haber sido modificados o eliminados. Es mejor que pongas un binmode(FILE); después del open(). Y lo mismo a la salida. Pon un binmode(STDOUT); antes del print() de la línea 18
    * aunque estás cargando el módulo CGI, realmente no lo estás usando en ningún sitio, así que esa línea también sobra

Quedaría algo así (no probado):
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4.  
  5. my $file;
  6. {
  7.     local $/;
  8.     open my $FILE, '<', '/tmp/archivos_xls/prueba.xls'  or die "ERROR: $!\n";
  9.     binmode $FILE;
  10.     $file= <$FILE>;
  11.     close   $FILE;
  12. }
  13.  
  14. binmode STDOUT;
  15.  
  16. print "Content-type: application/msexcel\n";                         # application/vnd.ms-excel
  17. print "Content-Disposition: attachment; filename='prueba.xls'\n";
  18. print "\n";
  19. print $file;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Aún tengo alguna duda sobre si ese Content-type es el correcto... bueno, he dejado indicados los dos.

Otra cosa es que el archivo Excel lo quieras crear en el momento, es decir, en la propia llamada al cgi. En ese caso sí que necesitas cargar el módulo Spreadsheet::WriteExcel, para generar el archivo Excel en memoria, y luego mandarlo al usuario (ejemplo).
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Abrir archivo xls con Spreadsheet::WriteExcel

Notapor silva » 2013-01-23 19:16 @844

¡¡¡Gracias por tu respuesta y valioso tiempo!!!

He detectado el problema, pero no sé cómo resolverlo.

Mi aplicación CGI se basa en un formulario donde el usuario ingresa ciertos parámetros, con los cuales yo genero un archivo Excel que el usuario necesita y se lo abro para que lo vea.

Necesito tanto el módulo CGI, como el módulo Spreadsheet::WriteExcel para crear el archivo xls. Todo esto se hace correctamente porque estoy viendo el archivo que se genera al ejecutar el script, pero cuando al finalizar la generación del xls quiero abrirlo automáticamente, éste no se abre, tira error, aunque existe, lo veo creado bien y puedo abrirlo desde afuera.

Es decir, lo que no funciona es la apertura automática del archivo, sintaxis de apertura que procede a la sintaxis de creación del mismo con Spreadsheet::WriteExcel.


A groso modo pongo líneas de código:
Sintáxis: [ Descargar ] [ Ocultar ]
  1.  
  2. while () {... 
  3.  
  4.   if { .. 
  5.  
  6.  
  7.   # Conformo el archivo XLS 
  8.   #---------------------------------------------------------------------- 
  9.   my $DirXLS = '/tmp/archivos_pdf'; 
  10.   my $FileXLS = "Despacho_" . sprintf("%02d", $dia ) . sprintf("%02d", $mes ). $anio . 'xls' ; 
  11.  
  12.      if ($open_file eq 'T') { 
  13.        # Create a new workbook and add a worksheet 
  14.        $workbook = Spreadsheet::WriteExcel->new($DirXLS . '/' . $FileXLS); 
  15.  
  16.        $worksheet = $workbook->add_worksheet(); 
  17.  
  18.        # Create a format for the column headings 
  19.        $header = $workbook->add_format(); 
  20.        $header->set_bold(); 
  21.        $header->set_size(10); 
  22.        $header->set_color('blue'); 
  23.  
  24.        # Create a format para campos numerico entero 
  25.        $f_numerico = $workbook->add_format(); 
  26.        $f_numerico->set_align('right'); 
  27.        $f_numerico->set_size(9); 
  28.        $f_numerico->set_num_format('General'); 
  29.  
  30.  
  31.        # Create a format para campos monetarios 
  32.        $f_monetario = $workbook->add_format(); 
  33.        $f_monetario->set_align('right'); 
  34.        $f_monetario->set_size(9); 
  35.        $f_monetario->set_num_format('0.00'); 
  36.  
  37.        # Create a format para campos de volumen 
  38.        $f_volumen = $workbook->add_format(); 
  39.        $f_volumen->set_align('right'); 
  40.        $f_volumen->set_size(9); 
  41.        $f_volumen->set_num_format('0.0000'); 
  42.  
  43.        # Create a format for the stock volume 
  44.        $f_alfabetico = $workbook->add_format(); 
  45.        $f_alfabetico->set_size(9); 
  46.        $f_alfabetico->set_align('left'); 
  47.  
  48.        $filler= 0; 
  49.        # Write encabezados 
  50.        $worksheet->write(0, 0, 'TIPO', $header); 
  51.        $worksheet->write(0, 1, 'NRO_CTACTE', $header); 
  52.        $worksheet->write(0, 2, 'CEMIS_CBTE', $header); 
  53.        $worksheet->write(0, 3, 'NRO_CBTE', $header); 
  54.        $worksheet->write(0, 4, 'LETRA_CBTE',$header); 
  55.        $worksheet->write(0, 5, 'FECHA_CBTE', $header); 
  56.        $worksheet->write(0, 6, 'RAZSOC_DEST', $header); 
  57.        $worksheet->write(0, 7, 'DOMIC_DEST', $header); 
  58.        $worksheet->write(0, 8, 'LOCAL_DEST', $header); 
  59.        $worksheet->write(0, 9, 'Filler',$header); 
  60.        $worksheet->write(0, 10, 'CODPOS_DEST', $header); 
  61.               
  62.        # Write filas 
  63.        $worksheet->write($fila, 0, $tipo, $f_alfabetico); 
  64.        $worksheet->write($fila, 1, $nro_ctacte, $f_alfabetico); 
  65.        $worksheet->write($fila, 2, $cemis_cbte , $f_numerico); 
  66.        $worksheet->write($fila, 3, $nro_cbte, $f_numerico); 
  67.        $worksheet->write($fila, 4, $letra_cbte, $f_alfabetico); 
  68.        $worksheet->write($fila, 5, $fecha_cbte, $f_numerico); 
  69.        $worksheet->write($fila, 6, $razsoc_dest, $f_alfabetico); 
  70.        $worksheet->write($fila, 7, $domic_dest, $f_alfabetico); 
  71.        $worksheet->write($fila, 8, $local_dest, $f_alfabetico); 
  72.        $worksheet->write($fila, 9, $filler, $f_numerico); 
  73.        $worksheet->write($fila, 10, $codpos_dest, $f_numerico); 
  74.         
  75.        $fila = $fila + 1; 
  76.  
  77.        $open_file = 'F'; 
  78.  
  79.      } 
  80.      else { 
  81.        # Write filas 
  82.        $worksheet->write($fila, 0, $tipo, $f_alfabetico); 
  83.        $worksheet->write($fila, 1, $nro_ctacte, $f_alfabetico); 
  84.        $worksheet->write($fila, 2, $cemis_cbte, $f_numerico); 
  85.        $worksheet->write($fila, 3, $nro_cbte, $f_numerico); 
  86.        $worksheet->write($fila, 4, $letra_cbte, $f_alfabetico); 
  87.        $worksheet->write($fila, 5, $fecha_cbte, $f_numerico); 
  88.        $worksheet->write($fila, 6, $razsoc_dest, $f_alfabetico); 
  89.        $worksheet->write($fila, 7, $domic_dest, $f_alfabetico); 
  90.        $worksheet->write($fila, 8, $local_dest, $f_alfabetico); 
  91.        $worksheet->write($fila, 9, $filler, $f_numerico); 
  92.        $worksheet->write($fila, 10, $codpos_dest, $f_numerico); 
  93.        
  94.        $fila = $fila + 1; 
  95.  
  96.      }  # end mpresion de linea 
  97.  
  98.  
  99.  
  100.    } # END if despachar 
  101.  
  102.    $i = $i + 1 ; 
  103.    $j = $j + 1; 
  104.  
  105.   } # END while cant- de envioc 
  106.  
  107.  
  108.  
  109.  # Abro en pantalla el archivo XLS creado Esto no funciona abriendo el archivo generado anteriormente. Si funciona si abro un archivo generado antes, no reciente 
  110.  #----------------------------------------------------------------------------- 
  111.  
  112.  my $pathXLS = $DirXLS . '/' . $FileXLS; 
  113.   
  114.  open XLS, $pathXLS or die "Error, No puede abrir archivo XLS" ; 
  115.  binmode(XLS); 
  116.   
  117.  my $fileSize = -s $pathXLS; 
  118.  print "Content-type: application/octet-stream\r\n"; 
  119.  print "Content-Length: ".$fileSize."\r\n"; 
  120.  print "Content-disposition: attachment; filename=$pathXLS\r\n"; 
  121.  print "Content-Transfer-Encoding: binary\r\n"; 
  122.  print "Pragma: no-cache\r\n"; 
  123.  print "\r\n"; 
  124.  print while (<XLS>); 
  125.  close XLS; 
  126.  
  127.  
  128.  



¿Me comprendes? ¡¡¡Gracias!!!
silva
Perlero nuevo
Perlero nuevo
 
Mensajes: 82
Registrado: 2011-05-24 05:59 @291

Re: Abrir archivo xls con Spreadsheet::WriteExcel

Notapor explorer » 2013-01-24 11:05 @503

Por el código, veo que haces lo tradicional: primero generas el archivo XLS en disco, y luego lo abres para enviarlo al navegador web. De ese código, lo que falta por hacer es un $workbook->close() para que el módulo grabe todos los cambios a disco.

Pero, te repito, que no necesitas hacerlo de esa manera.

Puedes generar el archivo XLS en memoria, y no tener que grabarlo en disco. Solo tienes que 1) enviar las cabeceras, y 2) crear el objeto Spreadsheet::WriteExcel con destino la salida estándar. Así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     print "Content-type: application/vnd.ms-excel\n";
  2.     # The Content-Disposition will generate a prompt to save the file. If you want
  3.     # to stream the file to the browser, comment out the following line.
  4.     print "Content-Disposition: attachment; filename=$filename\n";
  5.     print "\n";
  6.  
  7.     # Create a new workbook and add a worksheet. The special Perl filehandle - will
  8.     # redirect the output to STDOUT
  9.     #
  10.     my $workbook  = Spreadsheet::WriteExcel->new(\*STDOUT);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

(Líneas extraídas del ejemplo cgi.pl de la página Spreadsheet::WriteExcel::Examples)

De todas maneras, si quieres grabar el resultado a disco, entonces puedes hacerlo como hasta ahora, pero poniendo el close().

Fíjate en lo que pone en los comentarios: el envío de la cabecera 'attachment' provoca que, al usuario, le aparezca el formulario de "Guardar como...", para que elija nombre y destino del archivo que está recibiendo. ¿Es ese el comportamiento que quieres que ocurra? Como hablas de la "apertura automática", entendí que te referías a que se ejecutara el Excel con ese archivo.

Otro caso, que acabo de darme cuenta. ¿Estás generando los archivos en la misma máquina en donde los quieres ver?
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Abrir archivo xls con Spreadsheet::WriteExcel

Notapor silva » 2013-01-24 13:53 @620

Gracias. Resuelto.

1- La opción $workbook->close() anda correctamente

2- La opción de generar el archivo XLS en memoria. Solo se imprimen la primera y segunda línea del archivo, es decir las líneas que se encuentran dentro de la condición if() verdadera. Las demás líneas conformantes del archivo corresponden al else{} y no se están imprimiendo.

Pero con la opción 1 está resuelto. ¡¡¡Gracias!!!
silva
Perlero nuevo
Perlero nuevo
 
Mensajes: 82
Registrado: 2011-05-24 05:59 @291

Re: Abrir archivo xls con Spreadsheet::WriteExcel

Notapor explorer » 2013-01-24 16:17 @720

Es que el código que has mostrado no da pistas de la forma en que creas las hojas.

Vemos que el if() depende de una variable llamada $open_file. Si esa variable es igual a 'T', entonces es cuando creas el archivo. Si no, no se crea el archivo porque se supone que ya lo está.

Pero el resultado debería ser igual que grabarlo a disco. Bueno, no: si no lo grabas a disco, el resultado es más rápido (te ahorras el proceso de grabar a disco).
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Módulos

¿Quién está conectado?

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