[bcn-pm] arxius amb registres d'amplada coneguda

Xavier Noria fxn at hashref.com
Thu Sep 4 16:50:53 CDT 2003


En Miquel va demanar a l'anterior reunio per una manera rapida de llegir 
un registre en un arxiu en el qual tots els registres tenen la mateixa 
longitut i camps d'amplada fixa i coneguda.

Varem comentar que seek() i read() podrien servir pero que ho parlariem 
a la llista, aixi que envio un codi que il.lustra el tema.

Si fem anar el salt de linia com a separador de registres, o si es un 
altre pero els camps mateixos poden dur salts de linia, tal com varen 
dir a la reunio cal que treballem sempre en mode binari, tant per a 
escriure com per a llegir.

Aixo es aixi perque encara que print() i read() s'ho fan per a que en el 
codi un salt de linia sempre sigui eq "\n" en qualsevol plataforma si es 
treballa en mode text, resulta que seek() no te en compte aquest tema i 
no hi ha manera portable de saltar d'una tacada a l'inici del registre 
que volem llegir.

Com a curiositat, hi ha comentada una alternativa a read() que fa anar 
un cas especial d'assignacio a $/.

-- fxn

El suposat fitxer foo.dat s'enten que conte registres del tipus

aaaBBBBccc
dddEEEEfff
gggHHHHiii
etc.

de tres camps cadascuna, i que ha estat creat en mode binari.

#!/usr/bin/perl

use strict;
use warnings;

use Fcntl ':seek';

# Longitut d'un registre, sense comptar el separador de registres.
use constant RECORD_SIZE => 10; # bytes

# Longitut del separador de registres. Si fem anar "\n" tenint l'arxiu
# en mode binari a l'escriure i llegir aquest 1 es portable.
use constant RECORD_SEP_SIZE => 1; # bytes

# Plantilla per a unpack().
#
# A l'exemple hi ha tres camps a cada registre, un de 3 bytes, l'altre
# de 4, i l'ultim de 3. Ha de sumar el mateix que RECORD_SIZE.
use constant PACK_TEMPLATE => 'A3A4A3';

# Passem el registre que volem llegir com a argument. Prenem com a
# conveni que el primer es el 0.
my $record_to_read = shift;

# Obrim el fitxer amb les dades.
open DAT, 'foo.dat' or die $!;

# I abans de res el posem en mode binari.
binmode DAT;

# Movem el cursor al principi del registre que es vol llegir (veure
# perldoc -f seek).
seek DAT, $record_to_read*(RECORD_SIZE + RECORD_SEP_SIZE), SEEK_SET;

# Un cop estem en el lloc, llegim els bytes que calen.
my $record;
read DAT, $record, RECORD_SIZE;

# Aixo tambe es podria fer modificant $/ si volguessim, com a
# my $record = do { local $/ = \RECORD_SIZE; <DAT> };

# Amb unpack() podem recuperar els camps d'amplada coneguda de manera
# eficient.
my @fields = unpack PACK_TEMPLATE, $record;

# Aixo imprimeix el segon camp, el que te quatre caracters.
print $fields[1];




More information about the Barcelona-pm mailing list