[caracas-pm] [l-desarrollo] Perl - uso de filehandlers anónimos para evitar archivos temporales

Ernesto Hernández-Novich emhnemhn at gmail.com
Fri Jan 14 12:57:13 PST 2011


On Fri, 2011-01-14 at 11:33 -0600, Juan Luis Zamora wrote:
> ¿Cual es la mejor manera de progresivamente ir escribiendo a un filehandler (a
> medida que vaya sacando datos a través del programa), pero que éste,
> no esté escribiendo a un archivo en disco sino a una cadena tipo
> lista?.

Interpreto a una cadena, pero agregando al final.

> Actualmente lo estoy implementando así y parece funcionar bien:
> 
> my $string;
> open (my $fh,'>',\$string) || "no puedo escribir en la lista: $!";

Eso hace exactamente lo que tu quieres. Es un ejemplo de DWIM [1]
combinado con la regla de la mínima sorpresa :-)

Al usar open() en un Perl moderno (5.10.0 o mejor), los filehandles
generados en realidad son objetos en la jerarquía IO::Handle.
Dependiendo del tercer argumento de open (en este caso, una referencia a
un escalar), el nuevo open() decide cuál subclase utilizar, y en este
caso utiliza IO::String.

Pero supongo que no tuviste que leer nada, porque supusiste
(correctamente) "Perl *sabe* lo que quiero hacer" y la cosa simplemente
funciona.

> No estando seguro que sea la mejor manera de manejar esto, leyendo un
> poco encontré que hay un modulo core IO::Handle, pero por alguna razón
> al tratar de sacar un filehandler anónimo, me daba error:
> 
> Bareword "IO::Handle" not allowed while "strict subs" in use

El manual de IO::Handle es claro al indicar que esta clase no debe ser
instanciada, pues simplemente sirve de base para las clases
especializadas.

> ¿Tendrán alguna sugerencia de como tratar esto de la mejor manera?, el
> objetivo es ir escribiendo sobre dicha lista a medida de que se van
> obteniendo datos tipo texto de varias funciones que hacen auditorias
> sobre bases de dato entre otras cosas, y al final, cifrarlo y
> guardarlo así para no escribir texto claro en disco.

La clase especializada que estás buscando es IO::Scalar

use IO::Scalar;
my $s  = "TIMTOWTDI:\n";
my $sh = new IO::Scalar \$s;
$sh->print("There Is More Than One Way To Do It");
$sh->print(", FTW!\nKTHXBYE!\n");
print $s;

Incidentalmente IO::Handle junto con sus clases derivadas logran algo
que muy pocos lenguajes de programación tienen: completa ortogonalidad
entre los tipos de datos y las operaciones de I/O cumpliendo al pie de
la letra con la filosofía Unix de "todo es un archivo". En efecto
IO::Scalar permite que una variable sea trabajada como un archivo, así
que *código* que fue pensado para trabajar con archivos puede operar
*sin* modificación sobre una variable (para leer, escribir y ambas cosas
con desplazamientos arbitrarios) con el único proviso de contar con
memoria suficiente.

Para aquellos que intuyen que la OO es superflua en un problema como
este, hay una interfaz para IO::Scalar absolutamente
imperativo/funcional (basada en la magia del hombre blanco llamada
'tie') de manera que el mismo programa anterior puede escribirse

use IO::Scalar;
my $s  = "TIMTOWTDI:\n";
my $sh = new IO::Scalar \$s;
print $sh "There Is More Than One Way To Do It";
print $sh ", FTW!\nKTHXBYE!\n";
print $s;

De hecho, gracias a la sobrecarga de la "conversión implícita a cadena",
si haces

print "$sh"

se muestra el string asociado al filehandle :)

Se pueden hacer cosas similares con listas, arreglos de escalares y
operaciones atómicas (man IO::Stringy)

[1] Do What I Mean
-- 
Ernesto Hernández-Novich - @iamemhn - Unix: Live free or die!
Geek by nature, Linux by choice, Debian of course.
If you can't aptitude it, it isn't useful or doesn't exist.
GPG Key Fingerprint = 438C 49A2 A8C7 E7D7 1500 C507 96D6 A3D6 2F4C 85E3



More information about the caracas-pm mailing list