[SP-pm] Write Binary!

Igor Sutton Lopes igor.sutton em gmail.com
Quinta Abril 26 09:42:44 PDT 2007


On Apr 26, 2007, at 5:19 PM, Igor Sutton Lopes wrote:

>
> On Apr 26, 2007, at 4:43 PM, Henrique Rennó wrote:
>
>> Fala Fred!
>>
>> Existe um programa muito usado aqui no trabalho chamado GrADS.  
>> Basicamente ele é um plotador, um gerador de gráficos. Para ele  
>> plotar os gráficos, os valores a serem trabalhados devem estar em  
>> um arquivo no formato binário (existem outros formatos que ele lê  
>> também mas binário é o mais geral).
>>
>> Os programas que faço para trabalhar com esses dados estão todos  
>> em C que passei dos que estavam em FORTRAN. No FORTRAN deve-se  
>> abrir o arquivo passando parâmetros tipo 'stream' and  
>> 'unformatted', sem esses parâmetros não dá certo. Já em C seria  
>> apenas a opção "b" para o fopen. Para escrever no arquivo, em  
>> FORTRAN usa-se o write passando para ele um vetor(M*N) onde N é o  
>> número de elementos da matriz de 2 dimensões com M linhas e N  
>> colunas na ordem linha 1, colunas 1-N, linha2, colunas 1-N, ...,  
>> linhaM, colunas 1-N, etc. Em C não dá certo usando o fscanf ou  
>> qualquer outra função que utiliza formatação, já o fwrite funciona  
>> como eu havia descrito antes: fwrite(matriz, sizeof(float), M*N,  
>> fpointer)
>>
>> Agora estou querendo passar para perl apenas por aprendizado.  
>> Tentei o pack com formatação "B*" como o Luis Motta disse e não  
>> funcionou.
>>
>
> Vamos lá, você quer armazenar um array mais ou menos assim:
>
> @data = (
>     [ 0, 1, 2, 3, 4 ], # linha1
>     [ 0, 1, 2, 3, 4 ], # linha2
>     [ 0, 1, 2, 3, 4 ], # linhaN
> );
>
> em formato binário, certo?
>
> Segundo a página manual do fwrite(3):
>
>      [snip]
>
>      size_t
>      fwrite(const void * restrict ptr, size_t size, size_t nmemb,
>          FILE * restrict stream);
>
>     [snip]
>
>      The function fwrite() writes nmemb objects, each size bytes  
> long, to the
>      stream pointed to by stream, obtaining them from the location  
> given by
>      ptr.
>
> Acredito que uma primeira tentativa seria:
>
> <code>
> use strict;
> use warnings;
>
> my @data = (
>     [ 0, 1, 2, 3, 4 ],    # linha1
>     [ 0, 1, 2, 3, 4 ],    # linha2
>     [ 0, 1, 2, 3, 4 ],    # linhaN
> );
>
> my $binary_data;
> for my $line (@data) {
>
>     # cria o pattern para o pack, baseado no numero
>     # de elementos que este possui. perldoc -f pack para
>     # significado de "f"
>     my $pack_pattern = "f" x scalar @{$line};
>
>     # armazena o resultado do pack aplicado ao
>     # pattern acima, utilizando os elementos da
>     # linha
>     $binary_data .= pack( $pack_pattern, @$line );
> }
> open my $fh, ">", "/tmp/output.bin" or die $!;
> binmode($fh);
> print $fh $binary_data;
> close $fh or warn $!;
> </code>
>
> Veja se serve prá alguma coisa, ou chega perto :-)

Bom, prá ler o arquivo binário gerado com este programa, você pode  
utilizar o seguinte pedaço de código:

<code>
use strict;
use warnings;

use Data::Dumper;

open my $fh, "<", "/tmp/output.bin" or die $!;
binmode($fh);
my @contents = unpack( "f*", <$fh> );
my @data;
while (@contents) {
     push @data, [ splice( @contents, 0, 5 ) ];
}
print Dumper \@data;
close $fh or warn $!;
</code>

Acredito que sabendo a dimensão N do seu array bidimensional, você  
consegue até ler os seus arquivos gerados com os outros programas...

Para alterar o tamanho do array na representação, modifique o  
terceiro argumento do comando splice() no código acima, modificando-o  
para o tamanho N e diga-nos o resultado :-)

Boa sorte!

--
Igor Sutton
igor.sutton em gmail.com



-------------- Próxima Parte ----------
Um anexo em HTML foi limpo...
URL: http://mail.pm.org/pipermail/saopaulo-pm/attachments/20070426/d56a5977/attachment-0001.html 
-------------- Próxima Parte ----------
Um anexo não texto foi limpo...
Nome  : PGP.sig
Tipo  : application/pgp-signature
Tam   : 186 bytes
Descr.: This is a digitally signed message part
Url   : http://mail.pm.org/pipermail/saopaulo-pm/attachments/20070426/d56a5977/attachment-0001.bin 


Mais detalhes sobre a lista de discussão SaoPaulo-pm