Excluir Dados em C [RESOLVIDO]

1. Excluir Dados em C [RESOLVIDO]

Fabricio de Medeiros
FabiC

(usa Ubuntu)

Enviado em 24/11/2015 - 17:09h

Tenho que fazer um projeto de cadastro de funcionários em C, que tenha incluir, excluir...
Tô com um problema na parte de excluir, quando coloco a matricula para excluir o programa não exclui, a matricula só é excluida quando eu reexecuto o algoritmo e tem vezes que ele duplica a matricula que coloquei para excluir. Podem da um help(código a baixo)


FILE *pf;
FILE *temporario;
pf = fopen("C:\\Users\\fabricio\\Desktop\\Projeto C\\Dados\\Funcionarios.txt","r+");
temporario = fopen("C:\\Users\\fabricio\\Desktop\\Projeto C\\Dados\\FuncionariosTemporario.txt","a+");
formulario Dados;
int matricula,achou = 0;
rewind(pf);

if(pf == NULL){
printf("\t\t Erro ao abrir arquivo\n");
}

desenharTitulo();
printf("\t\t %c--------------------------------------%c\n",254,254);
printf("\t\t | ");printf("\t\t EXCLUIR");printf("\t\t |\n");
printf("\t\t %c--------------------------------------%c\n",254,254);
printf("\n");
printf("\t\t |--------------------------------------|\n");
printf("\t\t |MATRÍCULA : ");
scanf("%d",&matricula);
rewind(pf);

while(fread(&Dados,sizeof(Dados),1,pf) != 0){
if(Dados.matricula != matricula){
fwrite(&Dados,sizeof(Dados),1,temporario);
}else{
printf("\t\t |--------------------------------------|\n");
printf("\t\t excluido com sucesso");
achou = 1;
}
}
fclose(pf);
fclose(temporario);
if(achou == 1){
remove("C:\\Users\\fabricio\\Desktop\\Projeto C\\Dados\\Funcionarios.txt");
rename("C:\\Users\\fabricio\\Desktop\\Projeto C\\Dados\\FuncionariosTemporario.txt","C:\\Users\\fabricio\\Desktop\\Projeto C\\Dados\\Funcionarios.txt");
}else{
printf("matricula não encontrada\n");
}


  


2. Re: Excluir Dados em C

Paulo
paulo1205

(usa Ubuntu)

Enviado em 25/11/2015 - 10:06h

Alguns comentários:

1) Você repete as mesmas constantes strings várias vezes no programa, e são constantes longas, excelentes vítimas de erros de digitação (para quem escreve) e falta de atenção (para quem escreve e quem lê o código), além de dificultar a manutenção do código, se houver necessidade de alterar os nomes dos arquivos, que implica ter de mudar a mesma coisa em vários lugares diferentes. Minha sugestão é que você declare símbolos constantes ou macros com esses nomes, e use tais símbolos quando for operar com os arquivos.

/* Exemplo com macros */
#define DATA_FILENAME "C:\\Users\\fabricio\\Desktop\\Projeto C\\Dados\\Funcionarios.txt"
#define TMPDATA_FILENAME "C:\\Users\\fabricio\\Desktop\\Projeto C\\Dados\\FuncionariosTemporarios.txt"

/* ... */

FILE *fp=fopen(DATA_FILENAME, "r");
FILE *tfp=fopen(TMPDATA_FILENAME, "w");

/* ... */

remove(DATA_FILENAME);
rename(TMPDATA_FILENAME, DATA_FILENAME);


2) Se você não vai alterar o arquivo através do ponteiro fp, não precisa abri-lo com modo "r+"; basta usar "r". Já o arquivo temporário, que não será lido, pode ser aberto em modo de escrita com remoção de qualquer conteúdo anterior, o que sugere que "w" deve ser usado, em lugar de "a+".

3) Por outro lado, como você parece estar usando Windows e seus arquivos contêm dados binários, provavelmente você deveria usar sempre o flag binário na especificação de modo (e.g. "wb" em lugar de "w", "r+b" em lugar de "r+" etc.). Caso contrário, se o modo default de abertura de arquivos for texto (geralmente o é, no Windows), você pode se deparar com algumas traduções inesperadas na hora de escrever nos ou ler dos arquivos certos bytes ou sequências de bytes.

4) O teste de se pf é nulo deveria ser movido para um ponto do programa anterior à realização de operações sobre ele, ou mesmo de abrir o arquivo temporário. Aliás, por que não testar também se o arquivo temporário foi aberto com sucesso?

5) Além disso, a resposta ao teste acima não deveria ser apenas imprimir uma mensagenzinha. Ela deveria impedir a execução do que vem depois -- especialmente porque o que vem depois inclui o apagamento do arquivo original e sua substituição por outra coisa.

6) O loop de cópia dos registros parece estar essencialmente correto (desde que o campo com a matrícula seja de um tipo de dados que se possa comparar com o operador !=; se ele for um campo com uma string, você deveria usar a função strcmp() em vez do operador). No entanto, eu sugiro que você seja mais cauteloso contra perda de dados, tomando os cuidados abaixo.

    a) Lembre-se de que algumas linhas abaixo você vai substituir o arquivo original pelo arquivo novo. Por isso, verifique se cada uma das chamadas a fwrite() executou com sucesso. Qualquer falha de escrita deve provocar a interrupção da execução e preservação do arquivo original.

    b) Não convém imprimir a mensagem de que o registro foi excluído durante um loop que ainda está construindo o arquivo substituto. Eu a guardaria até o momento em que se tiver certeza de que o arquivo substituto, depois de construído plenamente e com sucesso, entrou no lugar do original.

    c) Você usa as chamadas a fread() como condição de controle do loop. Isso está OK, mas você então terá de checar, após o fim do loop, se a última chamada retornou valor zero porque realmente chegou ao fim de arquivo ou se houve erro de leitura. Teste primeiro com ferror(), e depois confirme com feof(). Se o primeiro teste der verdadeiro, ocorreu um erro e o arquivo original deveria ser preservado. Se o segundo der falso, então o arquivo original tem grandes chances de estar corrompido (o tamanho total não é múltiplo do tamanho de cada registro, situação que pode acontecer em decorrência de não especificar modo de operação binário na hora de abrir o arquivo), e você terá de decidir como proceder nessa situação.

7) Pode parecer surpreendente a princípio, mas a cópia de registros só termina realmente depois que você chama fclose() sobre o arquivo temporário, porque é nesse momento que os buffers são esvaziados e a escrita em disco é realmente encaminhada para o sistema operacional. Por isso, você também deveria testar o valor de retorno dessa chamada.

8) Ainda para se proteger contra perda de dados, além de implementar as recomendações acima, eu cercaria de cuidados e avisos ao usuário a parte final, que efetua a troca dos arquivos. Se o seu programa fosse exclusivamente para o mundo UNIX, eu eliminaria a chamada a remove(), pois a de rename() seria suficiente para fazer atomicamente a substituição de um arquivo pelo outro, e sua eventual falha preservaria o arquivo original. No caso geral (no qual o Windows infelizmente se enquadra), porém, é necessário tirar o arquivo velho do caminho primeiro, e isso, por si só, já inevitavelmente abre espaço para perda de dados (imagine a situação em que falta luz ou computador trava entre a conclusão de remove() e a execução de rename()).


3. Re: Excluir Dados em C [RESOLVIDO]

Fabricio de Medeiros
FabiC

(usa Ubuntu)

Enviado em 27/11/2015 - 11:39h


Desculpa a demora para responder, provas na faculdade. Muito obrigado pelas dicas de organização melhorou muito o código, mas ainda não resolveu o problema, só resolveu uma parte quando eu troquei o "a+" pelo "w" e depois pelo "wb" resolveu o problema de duplicar, mas ele não guarda todos os dados EX: entrava com matricula 1 nome 1 salario 1 e quando ia incluir de novo ele apagava essa anterior e ficava nessa.


4. Re: Excluir Dados em C

Paulo
paulo1205

(usa Ubuntu)

Enviado em 27/11/2015 - 14:10h

FabiC escreveu:

Desculpa a demora para responder, provas na faculdade. Muito obrigado pelas dicas de organização melhorou muito o código, mas ainda não resolveu o problema, só resolveu uma parte quando eu troquei o "a+" pelo "w" e depois pelo "wb" resolveu o problema de duplicar, mas ele não guarda todos os dados EX: entrava com matricula 1 nome 1 salario 1 e quando ia incluir de novo ele apagava essa anterior e ficava nessa.


Seria bom você entender cada um dos modos de abertura de fopen(), para saber quando os usar. Já leu essa documentação? Eis um extrato da documentação que vem com o Linux.

       The argument mode points to a string beginning with one of the  follow-
ing sequences (possibly followed by additional characters, as described
below):

r Open text file for reading. The stream is positioned at the
beginning of the file.

r+ Open for reading and writing. The stream is positioned at the
beginning of the file.

w Truncate file to zero length or create text file for writing.
The stream is positioned at the beginning of the file.

w+ Open for reading and writing. The file is created if it does
not exist, otherwise it is truncated. The stream is positioned
at the beginning of the file.

a Open for appending (writing at end of file). The file is cre-
ated if it does not exist. The stream is positioned at the end
of the file.

a+ Open for reading and appending (writing at end of file). The
file is created if it does not exist. The initial file position
for reading is at the beginning of the file, but output is
always appended to the end of the file.

The mode string can also include the letter 'b' either as a last char-
acter or as a character between the characters in any of the two-char-
acter strings described above.


Entendeu? w e w+ sempre criam um arquivo zerado ou eliminam o conteúdo anterior de um arquivo que já exista. r e r+ nunca criam arquivo que ainda não exista, e sempre preservam seu conteúdo. w, w+ e r+ permitem escrever em qualquer posição do arquivo. a e a+ podem criar um arquivo que ainda não exista, e implicam escrever sempre no final do arquivo criado ou aberto (com a+ você pode mudar o ponteiro de leitura através de fseek() ou rewind(), mas a escrita continua sendo feita sempre no fim).

Em minha resposta anterior, eu tratei exclusivamente da rotina de exclusão, porque esse foi o tema da sua pergunta. Outras funções terão de chamar fopen() da maneira adequada ao que essa funções fizerem.


5. Re: Excluir Dados em C [RESOLVIDO]

Fabricio de Medeiros
FabiC

(usa Ubuntu)

Enviado em 28/11/2015 - 02:53h


Obrigado!!! consegui resolver era mesmos os modos do fopen()






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts