[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