Duvida com escrita e leitura de arquivos

1. Duvida com escrita e leitura de arquivos

william jussim
jussim

(usa Ubuntu)

Enviado em 25/09/2018 - 15:55h

Boa tarde pessoal,
Estou começando a estudar programação e estou com uma duvida em um projeto da faculdade.

Tenho um vetor de x posições de um tipo logico que criei chamada cliente. preciso que ao encerrar o programa todos os dados desse vetor sejam salvos em um arquivo de texto, e ao inicializar o programa ele faça a leitura desse arquivo.

Assistindo a algumas video aulas compreendi um pouco como salvar e fazer a leitura, mas somente de uma variavel ou struct, como no meu caso tenho um vetor estou com dificuldades em armazenar cada posição do vetor e depois fazer a leitura salvando os dados novamente no vetor de volta em suas respectivas posições.

Alguem poderia me ajudar, ou indicar algum material sobre isso.

Obrigado!


  


2. Re: Duvida com escrita e leitura de arquivos

Fernando
phoemur

(usa Debian)

Enviado em 25/09/2018 - 17:21h

Serialização é um tópico meio polêmico...

Você pode criar manualmente uma classe com RAII que ao ser criada tenta ler o arquivo e popular o vetor, e no destrutor chamar o método de serialização, salvando o estado atual no arquivo...

Você pode usar qualquer biblioteca de terceiros...

Você pode salvar como XML ou JSON ou qualquer formato que você inventar na hora, inclusive binário...

Você pode usar Boost::serialization

Você pode usar Boost::interprocess::vector para criar uma estrutura de dados persistente

Você pode fazer o que você quiser, porém é difícil opiniar sem saber o contexto no qual o programa vai ser usado...
Cada escolha tem seus prós e contras...

______________________
https://github.com/phoemur


3. Re: Duvida com escrita e leitura de arquivos

william jussim
jussim

(usa Ubuntu)

Enviado em 25/09/2018 - 17:36h

Na verdade é uma atividade da faculdade, estou iniciando agora com programação.
Consegui encontrar uns códigos na internet sobre isso mas não consegui entender bem o funcionamento.
O que eu preciso fazer é o seguinte, tenho um vetor do tipo cliente (que tem x variaveis) a ser populado pelo usuário.
Quando o programa for ser encerrado devo armazenas estas informações em um arquivo para que na próxima execução elas sejam lidas.

Para a escrita eu criei essa função:
void salvarCliente(cliente *cli, int *contCli){
FILE *dadosCli;
int cont = 0;
dadosCli = fopen("cliente.txt", "at");
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);

}
}

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.

E para a leitura do arquivo criei essa função:
void lerCliente(cliente *cli, int *contCli){
FILE *dadosCli = fopen("cliente.txt", "r");

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;
}
fclose(dadosCli);
*contCli =indice+1;
return indice;
}
else
printf("Erro");
}


Essa função eu alterei um código que encontrei na Net, mas não entendi por exemplo a função do comando size_t ou a criação da variavel P.
Ele popula somente o primeiro cliente no vetor. O resto não é lido.


4. Re: Duvida com escrita e leitura de arquivos

Paulo
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 (structs 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?

        return indice; 


Se a função tem tipo de retorno void, por que essa tentativa de retornar um valor inteiro?

    }
else
printf("Erro");
}









Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts