paulo1205
(usa Ubuntu)
Enviado em 26/09/2018 - 09:20h
Antes de mais nada, seria bom você deixar bem claro se está falando de C ou de C++. As respostas do nosso colega
phoemur apontam ótimas soluções em C++, mas que podem não lhe servir muito se você estiver usando C.
As funções
fwrite () e
fread () permitem escrever e ler
arrays inteiros num arquivo de uma só vez, ou uma quantidade limitada de elementos em cada operação. Você é quem decide se vai trabalhar com registro por registro ou com o
array inteiro numa única operação.
fwrite () e
fread () são excelentes para gravar registros armazenados na forma de estruturas (
struct s do C), desde que:
a)
[MUITO IMPORTANTE] todos os dados residam diretamente dentro da
struct (tipicamente implica que a estrutura não pode ter campos de tipos que sejam ponteiros ou que sejam usados com propósito de ponteiros);
b) você se lembre que o arquivo em que os registros serão/estão gravados é um arquivo binário, não de texto, o que implica tomar cuidados na hora de abrir o arquivo (que você não tomou — na verdade, você “tomou o cuidado” exatamente oposto!), de evitar a mistura de operações sobre dados binários com operações sobre texto (e.g. não deve usar
fprintf (),
fputs (),
fgets (),
fscanf () ou assemelhadas com esse arquivo) e de se deslocar no arquivo (
fseek ()) apenas em múltiplos do tamanho do registro;
c) como o arquivo não é de texto, você não deve tentar usar ferramentas externas que tentem tratá-lo como se fosse texto (editores de texto, comandos do S.O. como
cat ,
less ,
TYPE ,
more etc.).
jussim escreveu:
Para a escrita eu criei essa função:
void salvarCliente(cliente *cli, int *contCli){
Se você não altera o valor de
contCli dentro da função, por que passá-la como ponteiro? Seria melhor passar como simples inteiro.
FILE *dadosCli;
int cont = 0;
dadosCli = fopen("cliente.txt", "at");
Notou que aqui você força a função
fopen () a tratar seu arquivo como texto? Deveria ser o contrário: o modo deveria ser
"ab" (ou
"wb" , ou
"r+b" ).
if (dadosCli == NULL){
printf("Erro!!");
}
else{
do{
fwrite(&cli[cont], sizeof(cliente), 1, dadosCli);
//fwrite(&cli[cont],1,sizeof(cliente),dadosCli);
fclose(dadosCli);
cont++;
}while (cont < *contCli);
}
Se sua ideia é gravar o todos os
*contCli (ou simplesmente
contCli , se você acertadamente decidir deixar de usar ponteiro) clientes de uma só vez, você poderia fazer com uma operação só, trocando todo o bloco do
else pelo seguinte:
fwrite(cli, sizeof *cli, *contCli, dadosCli);
Contudo, para ficar melhor ainda, seria bom checar se a gravação foi bem sucedida, examinando o valor retornado pela função
fwrite (). Fica como exercício para você.
}
Ela salva os dados do cliente porém fica tudo escrito em uma linha e com carcteres ilegíveis. Não sei se desta forma ela esta correta.
Está correto porque o arquivo não terá formato de texto.
E para a leitura do arquivo criei essa função:
void lerCliente(cliente *cli, int *contCli){
FILE *dadosCli = fopen("cliente.txt", "r");
Aqui também você tem de dizer que o formato é binário (e.g. use
"rb" ).
if (dadosCli != NULL){
int indice =0;
cliente p;
while (1){
size_t r = fread(&p, sizeof(cliente), 1, dadosCli);
if(r < 1)
break;
else
cli[indice++] = p;
}
O laço de repetição está mais trabalhoso do que o necessário. Você poderia ter feito de uma forma mais canônica do seguinte modo.
while(fread(cli+indice, sizeof *cli, 1, dadosCli)==1)
indice++;
Outro modo de fazer, sem laço de repetição porque tenta ler todos os registros de uma vez (assumindo que
*contCli inicialmente contém o tamanho máximo do
array cli ), seria o seguinte.
*contCli=fread(cli, sizeof *cli, *contCli, dadosCli);
(Ao ser terminada a execução de
fread (), o valor de
*contCli é substituído com a quantidade de registros lidos com sucesso do arquivo.)
fclose(dadosCli);
*contCli =indice+1;
Não entendi esse "
+1 ". Por que você acha que precisa dele?
Se a função tem tipo de retorno
void , por que essa tentativa de retornar um valor inteiro?