The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NOMBRE

perlopentut - Recetas sencillas para abrir archivos y tuberías en Perl

DESCRIPCIÓN

En Perl, cualquier operación de E/S en un archivo debe hacerse a través de lo que se conoce como un identificador de archivo. Un identificador de archivo es un nombre interno para un archivo externo. La función open se encarga de establecer la asociación entre el nombre interno y el nombre externo, y la función close la cancela.

Para mayor comodidad, Perl incluye algunos identificadores de archivo especiales que ya están abiertos cuando se ejecuta un programa. Estos son STDIN, STDOUT, STDERR y ARGV. Como están abiertos de manera predefinida, no es necesario abrirlos para usarlos:

    print STDERR "Un mensaje de depuración.\n";

    print STDOUT "Escriba algo: ";
    $respuesta = <STDIN> // die "¿No hay entrada de datos?";
    print STDOUT "¡Gracias!\n";

    while (<ARGV>) { ... }

Como se puede ver en estos ejemplos, STDOUT y STDERR son identificadores de salida, y STDIN y ARGV son identificadores de entrada. Se escriben en letras mayúsculas porque son palabras reservadas de Perl, como lo son el array @ARGV y el hash %ENV. Sus asociaciones externas se configuraron en la shell.

Salvo estos casos especiales, debe abrir un identificador de archivo antes de usarlo. Hay muchas formas de llamar a la función open() de Perl, pero la variante más común es utilizar tres argumentos y un valor de retorno:

OK = open(IDENTIFICADOR, MODO, RUTA_ARCHIVO)

donde:

OK

será un valor definido si la función open se ejecutó correctamente, y undef en caso contrario;

IDENTIFICADOR

debe ser una variable escalar no definida que la función open rellenará si se ejecuta correctamente;

MODO

es el modo de acceso y el formato de codificación con el que se debe abrir el archivo;

RUTA_ARCHIVO

es el nombre externo del archivo que se va a abrir.

Gran parte de la complejidad de la función open reside en los muchos valores posibles del parámetro MODO.

Una última cosa antes de ver cómo se usa open: cuando se abre un archivo en Perl, no se bloquea de forma automática (normalmente). Vea perlfaq5 para obtener información sobre cómo bloquear un archivo.

Abrir archivos de texto

Abrir archivos de texto para lectura

Para leer un archivo de texto debe abrirlo en modo de solo lectura:

    my $nombre_archivo = "/ruta/al/archivo/de/texto";
    my $codificacion   = ":encoding(UTF-8)";
    my $identificador  = undef;     # se rellenará en caso de éxito

    open($identificador, "< $codificacion", $nombre_archivo)
        || die "$0: no se puede abrir $nombre_archivo para lectura: $!";

Al igual que en la shell, en Perl se usa "<" para abrir el archivo en modo de solo lectura. Si se abre correctamente, Perl le asigna un nuevo identificador de archivo y coloca una referencia a ese identificador en el argumento $identificador que estaba indefinido.

Ahora puede aplicar funciones como readline, read, getc y sysread a ese identificador. Probablemente la función de entrada más común es la que parece un operador:

    $linea = readline($identificador);
    $linea = <$identificador>;     # lo mismo

Como la función readline devuelve undef al final del archivo o en caso de error, a veces se usa de esta manera:

    $linea = <$identificador>;
    if (defined $linea) {
        # hacer algo con $linea
    }
    else {
        # se omite $linea porque no es válida
    }

Otra posibilidad es simplemente ejecutar die cuando se lee un valor indefinido:

    $linea = <$identificador> // die "no se encontró ninguna entrada";

Sin embargo, en un contexto en el que sea normal (y esté previsto) encontrarse EOF, la ejecución del programa no debe finalizar cuando no se encuentre ninguna entrada de datos. En ese caso, lo normal es salir de un bucle de entrada. Puede entonces comprobar si fue un error real el que provocó que el bucle terminase, y actuar en consecuencia:

    while (<$identificador>) {
        # hacer algo con los datos de $_
    }
    if ($!) {
        die "error inesperado al leer $nombre_archivo: $!";
    }

Nota sobre la codificación: Puede resultar pesado tener que especificar la codificación del texto cada vez que se abre un archivo. Con el pragma open se puede configurar una codificación predeterminada para la función open de forma que no sea necesario indicarla en cada ocasión:

    use open qw< :encoding(UTF-8) >;

Una vez hecho esto no es necesario especificar la codificación en el modo de apertura:

    open($identificador, "<", $nombre_archivo)
        || die "$0: no se puede abrir $nombre_archivo para lectura: $!";

Pero nunca se debe usar simplemente "<" sin haber configurado previamente una codificación predeterminada. De lo contrario, Perl no podrá determinar de cuál de los muchos tipos posibles de archivos de texto es el archivo y no podrá asignar correctamente los datos del archivo a caracteres reales con los que trabajar. Otros formatos comunes de codificación son "ASCII", "ISO-8859-1", "ISO-8859-15", "Windows-1252", "MacRoman" e incluso "UTF-16LE". Encontrará más información sobre codificaciones en perlunitut.

Abrir archivos de texto para escritura

Antes de escribir en un archivo hay que decidir qué hacer con su contenido actual. Las dos opciones básicas son conservarlo o sobrescribirlo.

Para preservar el contenido actual hay que abrir el archivo en modo anexar. Al igual que en la shell, en Perl se usa ">>" para abrir un archivo en modo anexar. Si el archivo no existe, ">>" lo crea.

    my $identificador  = undef;
    my $nombre_archivo = "/ruta/al/archivo/de/texto";
    my $codificacion   = ":encoding(UTF-8)";

    open($identificador, ">> $codificacion", $nombre_archivo)
        || die "$0: no se puede abrir $nombre_archivo para anexar: $!";

Ya puede escribir en ese identificador de archivo mediante print, printf, say, write o syswrite.

Como se ha indicado antes, si el archivo no existe, el modo anexar lo creará. Pero si el archivo ya existe, su contenido no se verá afectado, ya que el nuevo texto se anexará al final del texto actual.

Sin embargo, a veces queremos sobrescribir el contenido de un archivo. Para vaciar un archivo antes de empezar a escribir en él, ábralo en modo de solo escritura:

    my $identificador  = undef;
    my $nombre_archivo = "/ruta/al/archivo/de/texto";
    my $codificacion   = ":encoding(UTF-8)";

    open($identificador, ">  $codificacion", $nombre_archivo)
        || die "$0: no se puede abrir $nombre_archivo en modo de solo escritura: $!";

En este caso Perl también funciona igual que la shell: ">" sobrescribe un archivo existente.

Al igual que en el modo anexar, al abrir el archivo en modo de solo escritura puede aplicar las funciones print, printf, say, write o syswrite al identificador de archivo para escribir en el archivo.

¿Y el modo de lectura y escritura? Quizás lo mejor sea olvidarse de que existe, ya que es probable que el resultado de abrir archivos de texto en modo de lectura y escritura no sea lo que espera. Encontrará información detallada en perlfaq5.

Abrir archivos binarios

Si el archivo que se va a abrir contiene datos binarios en lugar de caracteres de texto, el argumento MODO de open cambia. En lugar de especificar la codificación, se indica a Perl que los datos son bytes puros.

    my $nombre_archivo = "/ruta/a/un/archivo/binario/";
    my $codificacion   = ":raw :bytes"
    my $identificador  = undef;     # se rellenará en caso de éxito

Se abre igual que antes, eligiendo entre "<", ">>" o ">":

    open($identificador, "< $codificacion", $nombre_archivo)
        || die "$0: no se puede abrir $nombre_archivo para lectura: $!";

    open($identificador, ">> $codificacion", $nombre_archivo)
        || die "$0: no se puede abrir $nombre_archivo para anexar: $!";

    open($identificador, ">  $codificacion", $nombre_archivo)
        || die "$0: no se puede abrir $nombre_archivo en modo de solo escritura: $!";

Como alternativa, se puede cambiar a modo binario en un identificador existente:

    binmode($identificador)  || die "no se puede pasar el identificador a modo binario";

Esto es especialmente útil para los identificadores que Perl abre automáticamente.

    binmode(STDIN)         || die "no se puede pasar STDIN a modo binario";
    binmode(STDOUT)        || die "no se puede pasar STDOUT a modo binario";

También se puede especificar en binmode una codificación explícita para cambiarla sobre la marcha. Esto no es exactamente modo "binario", pero usamos igualmente binmode para aplicarla:

  binmode(STDIN,  ":encoding(MacRoman)") || die "no se puede pasar STDIN a modo binario";
  binmode(STDOUT, ":encoding(UTF-8)")    || die "no se puede pasar STDOUT a modo binario";

Una vez abierto el archivo binario con el modo correcto, se pueden usar las mismas funciones de E/S de Perl que se usan con los archivos de texto. Sin embargo, es posible que se desee usar la función de lectura de tamaño fijo read en lugar de la función de lectura tamaño variable readline para la entrada de datos.

Veamos un ejemplo de cómo se copia un archivo binario:

    my $TAM_BUFER = 64 * (2 ** 10);
    my $entrada   = "/archivo/de/entrada";
    my $salida    = "/archivo/de/salida";

    my($id_entrada, $id_salida, $bufer);

    open($id_entrada,  "<", $entrada)
        || die "$0: no se puede abrir $entrada para lectura: $!";
    open($id_salida, ">", $salida)
        || die "$0: no se puede abrir $salida para escritura: $!";

    for my $id ($id_entrada, $id_salida)  {
        binmode($id)    || die "error de binmode";
    }

    while (read($id_entrada, $bufer, $TAM_BUFER)) {
        unless (print $id_salida $bufer) {
            die "no se puede escribir en $salida: $!";
        }
    }

    close($id_entrada)       || die "no se puede cerrar $entrada: $!";
    close($id_salida)        || die "no se puede cerrar $salida: $!";

Abrir tuberías

Pendiente.

Apertura de archivos de bajo nivel mediante sysopen

Pendiente. O se eliminará.

VEA TAMBIÉN

Pendiente.

AUTOR Y COPYRIGHT

Copyright 2013 Tom Christiansen.

Esta documentación es libre; puede redistribuirla y/o modificarla en los mismos términos que Perl.

TRADUCTORES

  • Joaquín Ferrero (Tech Lead)

  • Enrique Nell (Language Lead)