Manipulação de arquivos binários com o fopen

1. Manipulação de arquivos binários com o fopen

Paulo Henrique
MrCrawl3r

(usa Ubuntu)

Enviado em 13/04/2016 - 09:03h

Galera, peço desculpas por perguntar algo que pode ser bem simples para alguém que já tem uma boa base em C, mas o meu conhecimento é bem básico mesmo.

Estou com um problema que é o seguinte:
Tenho um arquivo com uma linha com a quantidade de numeros reais a serem lidas e as outras linhas contém estes números. Depois que eu ler estes dados, devo gravá-los em um arquivo binário e depois de gravar todos os números, fechar o arquivo, abrir novamente em outro método que deverá ler os arquivos do ultimo para o primeiro.

Fiz esta questão em Java, que é uma linguagem que tenho uma base melhor
Link para o cógigo em Java http://pastebin.com/CxcVW5Qw

Dúvidas
Porém, não estou conseguindo refazer o código em C, estou com problemas pois não sei se tem como gravar no arquivo o float direto, ao invés de uma String, pois vai ficar mais fácil para ler os dados depois.

Outra dúvida é se o fopen possui métodos como o RandomAccesFile do Java, que me permitem alterar a posição do cabeçote, retornam o tamanho do arquivo em Bytes e que retorna a posição que o cabeçote está apontando.

Código em C até aqui:
#include <stdio.h>

float readFloat () {
float numero;
scanf("%f",&numero);
return numero;
}

float readInt () {
int numero;
scanf("%d",&numero);
return numero;
}

void gravarArqSequencial (char url[]){
FILE *arq;
char c[64];
int quantidade, i;
float numero;

arq = fopen(url,"wb"); // cria arquivo binario para gravacao

quantidade = readInt();

if (arq == NULL)
printf("Erro! Problemas ao criar o arquivo.\n");
else {
for (i = 0; i < quantidade; i++)
{
numero = readFloat();
arq.fwrite("%f",&numero);
}
}
printf("%s\n", url);
}

int main(int argc, char const *argv[])
{
char url[] = "Arquivo_Sequencial.binc";

gravarArqSequencial(url);
return 0;
}



  


2. Re: Manipulação de arquivos binários com o fopen

Paulo
paulo1205

(usa Ubuntu)

Enviado em 13/04/2016 - 13:45h

MrCrawl3r escreveu:

Fiz esta questão em Java, que é uma linguagem que tenho uma base melhor
Link para o cógigo em Java http://pastebin.com/CxcVW5Qw


Infelizmente o acesso ao PasteBin é bloqueado aqui onde estou.

Porém, não estou conseguindo refazer o código em C, estou com problemas pois não sei se tem como gravar no arquivo o float direto, ao invés de uma String, pois vai ficar mais fácil para ler os dados depois.


Não sei como você fez em Java. Em C, o que você tem de fazer é se valer do fato de que o tamanho de um dado em ponto flutuante é fixo, e então tratar o arquivo como uma sequência de registros cujo tamanho é exatamente igual ao tamanho do valor de ponto flutuante que você usar. Se você usar double, por exemplo, que tipicamente tem tamanho de oito bytes, cada registro vai estar numa posição do arquivo que é múltipla de oito bytes: o primeiro registro na posição zero, o segundo na posição 8, o terceiro na posição 16, e assim por diante.

Se usar float, em vez de double, o tamanho dos registros provavelmente será de quatro bytes. Mas você não vai usar esses valores constantes no seu programa, é claro -- você certamente vai preferir usar o operador sizeof.

Outra dúvida é se o fopen possui métodos como o RandomAccesFile do Java, que me permitem alterar a posição do cabeçote, retornam o tamanho do arquivo em Bytes e que retorna a posição que o cabeçote está apontando.


Não programo usualmente em Java e, portanto, não conheço RandomAccessFile. Para a biblioteca padrão do C, em princípio, todo arquivo é um agregado de bytes a que se pode aceder de modo sequencial ou aleatório (a não ser que o sistema operacional não permita acesso direto, mas isso é resolvido em nível de SO, não de C). E não depende de fopen(), até porque fopen() é meramente uma função para obter uma referência a esse conjunto de bytes; não é uma classe ou tipo de dados.

As funções de manipulação de arquivos tipicamente usadas com arquivos de acesso aleatório são fread() (lê n registros de um tamanho especificado), fwrite() (escreve n registros de um tamanho especificado), fseek() (reposiciona o ponteiro de leitura e gravação em um _byte_ específico), e ftell() (informa a posição atual, medida em _bytes_, do ponteiro de leitura e gravação).

Código em C até aqui:
#include <stdio.h>

float readFloat () {
float numero;
scanf("%f",&numero);
return numero;
}

float readInt () {
int numero;
scanf("%d",&numero);
return numero;
}

void gravarArqSequencial (char url[]){
FILE *arq;
char c[64];
int quantidade, i;
float numero;

arq = fopen(url,"wb"); // cria arquivo binario para gravacao

quantidade = readInt();

if (arq == NULL)
printf("Erro! Problemas ao criar o arquivo.\n");
else {
for (i = 0; i < quantidade; i++)
{
numero = readFloat();
arq.fwrite("%f",&numero);


C não é uma linguagem orientada a objetos. A forma de invocar fwrite(), portanto, é como função comum.

fwrite(arq, tam_registro, n_registros, endereco_1o_registro) 


		}
}
printf("%s\n", url);
}


De forma geral, sobre a função acima, acho que você poderia rearrumá-la, talvez até desmembrando-a.

- Como você abre o arquivo de saída antes de ler a quantidade de valores a gravar, possivelmente seria mais coerente testar o sucesso da criação do arquivo de saída e eventualmente abortar o procedimento também antes de ler qualquer coisa. Alternativamente, você poderia ler a quantidade de valores antes de tentar abrir o arquivo de saída, e talvez nem mesmo tentar abrir o arquivo caso a quantidade informada de valores fosse zero.

- Para que serve o array de caracteres c?

- De uma função chamada gravarArqSequencial(), eu não esperaria muita interação com o o usuário, mas sim que ela tão-somente gravasse um arquivo sequencial. Aliás, há que se pensar até sobre isso: o arquivo é gravado sequencialmente, sim, mas ele tem natureza de acesso aleatório.

- O nome do parâmetro url não está errado, mas é enganoso. A biblioteca padrão do C, e fopen() em particular, não fala sobre lidar com URLs, mas com arquivos.

int main(int argc, char const *argv[]) 


O tipo de argv não está de acordo com o padrão. argv tem de ter um tipo com sentido de “array de strings”; o que você usou dá o sentido “array de strings constantes”. É válido para um programa em C manipular livremente não apenas o array de strings, mas também o conteúdo de cada string (isso pode não fazer sentido no sistema operacional, e pode até ser que provoque algum problema no caso de manipulação descuidada; mas não é o C que impõe limitações ou se preocupa com tais problemas).

{
char url[] = "Arquivo_Sequencial.binc";

gravarArqSequencial(url);
return 0;
}





3. Re: Manipulação de arquivos binários com o fopen

Paulo Henrique
MrCrawl3r

(usa Ubuntu)

Enviado em 13/04/2016 - 18:04h

Infelizmente o acesso ao PasteBin é bloqueado aqui onde estou.

Eu não havia colocado o código pois iria poluir um pouco este post, mas depois envio em outro comentário.

C não é uma linguagem orientada a objetos. A forma de invocar fwrite(), portanto, é como função comum.

Um dos meus erros estava aqui, obrigado por esclarecer.

De forma geral, sobre a função acima, acho que você poderia rearrumá-la, talvez até desmembrando-a.

Estava printando o caminho do arquivo apenas para testar se o código estava executando aquela parte, quando postei aqui no VOL esqueci de tirar rs. Mea culpa.


- Como você abre o arquivo de saída antes de ler a quantidade de valores a gravar, possivelmente seria mais coerente testar o sucesso da criação do arquivo de saída e eventualmente abortar o procedimento também antes de ler qualquer coisa. Alternativamente, você poderia ler a quantidade de valores antes de tentar abrir o arquivo de saída, e talvez nem mesmo tentar abrir o arquivo caso a quantidade informada de valores fosse zero.


Outro ponto importante que esqueci de informar é sobre o sistema que vai executar o código. Então... É um exercício da faculdade que eu travei para fazer, principalmente porque no primeiro período trabalhava apenas e Java e agora neste exercício o professor pediu para fazer em C me tirando totalmente da zona de conforto
O sitema executa o meu código e redireciona a entrada padrão para o arquivo, (algo +/- parecido como ./meu arquivo < arquivo_de_entrada_do_professor.txt > minhas_saidas.txt) então a leitura dos dados no método devem ser como se algém estivesse digitando no terminal mesmo, mas na realidade os dados partem do arquivo dele e compara a saída do meu programa que ao invés de escrever na tela, por causa do redirecionamento escreve em um arquivo de saída, depois compara estes arquivos para ver se está tudo certo.

- Para que serve o array de caracteres c?

Estava pegando uns exemplos na internet para tentar fazer eu mesmo e vi esse array de caracteres, achei que seria importante alguma hora, mas não vi que não seria necessário.

- De uma função chamada gravarArqSequencial(), eu não esperaria muita interação com o o usuário, mas sim que ela tão-somente gravasse um arquivo sequencial. Aliás, há que se pensar até sobre isso: o arquivo é gravado sequencialmente, sim, mas ele tem natureza de acesso aleatório.

Como explicado dois itens acima, não é o usuário quem digita, e sim o sistema que insere os dados pelo arquivo.

Obrigado pelas dicas, minha intenção de ter postado aqui no VOL era ter tirado as dúvidas que tinha sobre a linguagem C em relação aos arquivos e não procurar alguém que faça o programa todo para mim (caso o professor encontre este post kkk brincadeira). Sua ajuda foi de grande valor. Obrigado mesmo.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts