Jump to content

Eliminar registos no ficheiro


Go to solution Solved by passarito,

Recommended Posts

Posted

E nem tens de esperar muito.. 😁

A resposta curta é: Não eliminas.

A resposta longa é: Crias um ficheiro temporário do mesmo tipo, e para ele copias todos os registos menos o que queres eliminar.

Depois eliminas o ficheiro original, e por fim, renomeias o ficheiro temporário com o nome do original.

Ficheiros sequenciais têm essa pequena chatice.

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Posted (edited)

Eliminar automaticamente penso que não dá.

Podes é usar uma de das duas formas seguintes:

1. Eliminação fisica

1.1. Copias todos os registos excepto o que queres apagar para o novo ficheiro temporário

1.2. Apagas o ficheiro de dados

1.3. Renomeias o ficheiro temporário para o nome "oficial"

2. Eliminação virtual

2.1. No registo adicionas um campo boolean que será true quando o registo existe. Quando mandas apagar um registo passas esse campo a false.

Nesta opção poderás programar um item para te reduzir o numero de registos reais e consequentemente o tamanho usando a primeira opção

Edited by passarito
Posted

Boa tarde.

Nunopicado, percebi a tua forma de eliminar 😄 Vou tentar fazer como tu disseste se tiver alguma opinião meto a duvida no fórum para alguém me esclarecer 👍

CRLF, não percebi a tua segunda sugestão...

Abraço.

  • Solution
Posted

Antes de mais, o meu nome não é CRLF assim como o teu não é null 😉

Voltando ao que interessa, a 2ª opção será desta forma, imagina que o teu registo tem os campos Nome, Sexo, Idade, Morada. É só acrescentar um campo boolean, por exemplo, ativo.

Agenda=Record
 Nome: string[30];
 Sexo: Char;
 Idade: integer;
 Morada: String[100];
 activo: boolean;	 //Campo a adicionar para controlo das supressões (Verdadeiro-Mostra registo, Falso-Esconde registo)
end;
Posted

O método do @passarito tem uma vantagem e uma desvantagem, principalmente em ficheiros com muitos registos.

  • Vantagem: é muito mais rápido a "eliminar" registos - apenas muda o campo.
  • Desvantagem: ficam em disco os registos activos e os inactivos.

Knowledge is free!

Posted

O método do passarito é o que se usa em casos onde a informação é de importância elevada (por exemplo, um software de facturação, onde dados nenhuns podem ser apagados, apenas inactivados/escondidos).

Além da vantagem da rapidez e simplicidade de eliminar um registo (basta mudar o valor do campo), tem a vantagem de ser possível recuperar a informação, como se fosse uma reciclagem. É só voltar a mudar o valor e está lá tudo na mesma.

Usando este método, pode-se depois criar uma opção no programa que execute o primeiro método, em que efectivamente apaga todos os que estiverem marcados como inactivos. Isto usa "o melhor dos dois mundos", é rápido ao eliminar, e quando se achar necessário, é possível a eliminação efectiva.

Agora, uma nota:

Como diz o passarito, é preciso fazer um controlo de supressões.

Isto quer dizer que não basta por lá o campo e atribuir-lhe um valor, é necessário em TODAS as operações fazer a validação do campo e agir em conformidade.

Por exemplo, se estamos a fazer a listagem dos registos, é preciso mostrar apenas os que não estejam marcados como apagados.

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Posted

Boa tarde.

Antes de mais peço desculpa ao @passarito por no último comentário que fiz lhe ter chamado CRLF. 😕

Agora que já percebi o segundo método do passarito, acho melhor o método do verdadeiro e falso!

Ou seja, posso criar uma opção para o utilizador eliminar (esconder) o registo que deseja e posso criar outra opção para recuperar os registos que foram escondidos, como fosse uma reciclagem.

Se tiver mais dúvidas sobre este assunto esclareço aqui com vocês. 👍

Muito obrigado. 😄

Abraço!

Posted

Ou seja, posso criar uma opção para o utilizador eliminar (esconder) o registo que deseja e posso criar outra opção para recuperar os registos que foram escondidos, como fosse uma reciclagem.

Nem mais. 🙂

Num programa de faturação, por exemplo, é o único método admissível.

  • Vote 1

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Posted

Antes de mais peço desculpa ao @passarito por no último comentário que fiz lhe ter chamado CRLF. 😕

Tás desculpado!

Com este método "the sky is the limit".

Ora bem, vejamos, como o ficheiro de registos pode crescer muito e comprometer a velocidade do programa o que podes fazer?

Opção de acesso restrito, normalmente chamava-lhe "funções especiais" e tinha uma password.

Dentro dessa opção então poderás ter várias coisas, tais como, apagar definitivamente os registos utilizando o 1º método.

Mas ainda assim, não querendo perder essa informação apagada, queres reduzir o tamanho do ficheiro?

Solução: Arranjas um ficheiro de segurança e os registos normais copia-los para para o ficheiro oficial e os marcados como apagados adiciona-los ao tal ficheiro de segurança. Assim tens um ficheiro de trabalho de tamanho relativamente reduzido e um de segurança com tudo o que foi apagado que poderás consultar, importar, etc. a qualquer altura. Claro que dentro das funções especiais. Ora aí tens "The best of both worlds"

  • Vote 2
Posted

Como diz o passarito, é preciso fazer um controlo de supressões.

Isto quer dizer que não basta por lá o campo e atribuir-lhe um valor, é necessário em TODAS as operações fazer a validação do campo e agir em conformidade.

@nunopicado, não percebo o que queres dizer com isso... Podes explicar melhor?

Obrigado.

Posted

@nunopicado, não percebo o que queres dizer com isso... Podes explicar melhor?

Imagina que fazes uma função que te mostra todos os registos.

Normalmente, percorres o ficheiro e vais mostrando cada registo.

Com este sistema, tens de controlar o que está ou não marcado como apagado.

Ou seja, percorres o ficheiro e mostras apenas os que não estiverem marcados como apagados.

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Posted

Tal e qual como expliquei anteriormente

1. Eliminação fisica

1.1. Copias todos os registos excepto o que queres apagar para o novo ficheiro temporário

1.2. Apagas o ficheiro de dados

1.3. Renomeias o ficheiro temporário para o nome "oficial"

Posted (edited)

Boa tarde.

Ando de volta disto à algum tempo, nas calmas... Mas tenho de começar a apressar-me para mostrar o trabalho ao professor.

Estou a fazer o método 2 que o @passarito referiu, fiz o que vocês me explicaram mas não está a a resultar... Não percebo o porque!

Devo ter algo mal com o sinal true ou false...

Program Pzim ;

uses crt;

type dados_cliente = Record
     nomeC:string;
     num_biC:string;
     data_nasC:string;
     ruaC:string;
     loteC:string;
     cod_postalC:string;
     localidadeC:string;
     telemovelC:string;
     enderecoC:string;

  esconder:boolean;
 end;

   total_dados = Record
     cliente:dados_cliente;
end;

ficheiro_cliente = file of total_dados;
var  d:total_dados;

 f_cliente:ficheiro_cliente;

 opcao,fecho_principal:char;

Function exist_fich_cliente:boolean;
begin
 assign(f_cliente,'C:\stand\cliente.dat');
  {$I-}
 reset(f_cliente);
 close(f_cliente);
  {$I+}
 exist_fich_cliente:=(ioresult=0);
end;

Procedure menu_princial(var op:char);                                                         
begin
 clrscr;
 writeln (' --------------------------');
 writeln ('|      MENU PRINCIPAL      |');
 writeln (' --------------------------');
 writeln;
 writeln (' 1: Registrar um cliente');
 writeln;
 writeln (' A: Pesquisar Clientes');
 writeln;
 writeln (' E: Eliminar registros de clientes');
 writeln;
 readln (op);
end;

Procedure ler_cliente(var lc:total_dados);
var num_biC:string; fc:ficheiro_cliente; sinal:boolean;
begin
 assign(fc,'C:\stand\cliente.dat');
 reset(fc);
 seek(fc,0);
 sinal:=false;
 clrscr;
 writeln (' ----------------------------');
 writeln ('|    REGISTRAR UM CLIENTE    |');
 writeln (' ----------------------------');
 writeln;

 write ('> Numero de contribuinte: '); {verificar se já existe}                                                         
 readln (num_biC);
  while not(eof(fc)) do
   begin
    read(fc,lc);
    if (lc.cliente.num_biC = num_biC) then
    sinal:=true;
   end;

  if sinal = true then {se existir}
   begin
    writeln;
    writeln ('-- [ERRO] O numero de contribuinte ',num_bic,' ja existe. --');
   end;

  if sinal = false then {se não existir}
   begin
    with lc do
     begin
      cliente.num_biC := num_biC;
      cliente.esconder := false;
      write ('> Nome..................: ');
      readln (cliente.nomeC);
      write ('> Data de nascimento....: '); 
      readln (cliente.data_nasC);                   
      write ('> Rua...................: ');                 
      readln (cliente.ruaC);
      write ('> Lote..................: ');
      readln (cliente.loteC);
      write ('> Codigo postal.........: ');
      readln (cliente.cod_postalC);
      write ('> Localidade............: ');
      readln (cliente.localidadeC);
      write ('> Telemovel.............: ');
      readln (cliente.telemovelC);
      write ('> E-mail................: ');
     readln (cliente.enderecoC);
    end;
  close(fc);
 end;  
end;

Procedure escrever_cliente(ec:total_dados);
begin
with ec do
  begin
   writeln ('> Nome..................: ',cliente.nomeC);
   writeln ('> Numero de contribuinte: ',cliente.num_biC);
   writeln ('> Data de nascimento....: ',cliente.data_nasc);
   writeln ('> Rua...................: ',cliente.ruaC);
   writeln ('> Lote..................: ',cliente.loteC);
   writeln ('> Codigo postal.........: ',cliente.cod_postalC);
   writeln ('> Localidade............: ',cliente.localidadeC);
   writeln ('> Telemovel.............: ',cliente.telemovelC);
   writeln ('> E-mail................: ',cliente.enderecoC);
  end;
end;

Procedure esc_reg_fich_cliente(var fc:ficheiro_cliente);
var efc:total_dados; fecho:char;
begin 
 assign(fc,'C:\stand\cliente.dat'); 
 reset(fc);
 seek(fc,filesize(fc)); 
  Repeat
   ler_cliente(efc);
   write(fc,efc);
   writeln;
    Repeat
     writeln ('Deseja continuar a registrar clientes? S/N ');
     readln (fecho);
    Until (fecho='n') or (fecho='s') or (fecho='N') or (fecho='S');
  Until (fecho='N') or (fecho='n');                                               
 close(fc);
end;
{PESQUISAR CLIENTES REGISTRADOS}
Procedure pesquisar_clientes(var fc:ficheiro_cliente);
var pc:total_dados; sinal:boolean; pesqcliente,num_biC:string; oputi:char;
begin
 clrscr;
 assign(fc,'C:\stand\cliente.dat'); 
 reset(fc);
 seek(fc,0);
 sinal:=false;
 writeln (' ------------------------------ ');
 writeln ('|      Pesquisar clientes      |');
 writeln (' ------------------------------ ');
 writeln;
 write ('> Introduza o nome do cliente: ');
 readln (pesqcliente);
  while not(eof(fc)) do
   begin
    read(fc,pc);
    if (pc.cliente.nomeC = pesqcliente) and (pc.cliente.esconder = false) then
     begin
      writeln;
      escrever_cliente(pc);
      sinal:=true;
     end;  
   end;
   if (sinal=false) then
    begin
     writeln;
     writeln ('--- [ERRO] Nao existe nenhum cliente com esse nome na base de dados. ---');
    end;
  close(fc);  
end;

Procedure eliminar_cliente(var fc:ficheiro_cliente);
var ee:total_dados; var eliminar:char; num_biC:string;
begin
 clrscr;
 assign(fc,'C:\stand\cliente.dat');
 reset(fc);
 seek(fc,0);

 writeln (' ----------------------------');
 writeln ('|    ELIMINAR UM CLIENTE    |');
 writeln (' ----------------------------');
 writeln;
 writeln ('> Introduza o numero de contribuinte do cliente: ');
 readln (num_biC);

 while not(eof(fc)) do {PESQUISAR CLIENTES PARA OS ELIMINAR}
  begin
   read (fc,ee);
   if (ee.cliente.num_biC = num_biC) then
    begin
     writeln;
     escrever_cliente(ee);
    end;
  end;

  writeln;
  writeln ('- Carregue na tecla [E] para eliminar: ');
  readln (eliminar);

  if (eliminar = 's') or (eliminar = 'S') then
   begin
 ee.cliente.esconder := true; {esconder o registo}
    write(fc,ee); 
   end;
  close(fc);
end;


Begin
if (exist_fich_cliente) then
reset(f_cliente)
else
rewrite(f_cliente);
close(f_cliente);
Repeat
menu_princial(opcao);
case opcao of
 '1':esc_reg_fich_cliente(f_cliente);

 'a','A':pesquisar_clientes(f_cliente);

 'e','E':eliminar_cliente(f_cliente);
end;
writeln;
Repeat
 writeln ('- Deseja sair do programa? S/N ');
 readln (fecho_principal);
Until (fecho_principal='n') or (fecho_principal='s') or (fecho_principal='N') or (fecho_principal='S'); 
Until (fecho_principal='S') or (fecho_principal='s');   

End.

Quando o esconder tomar o valor a true esconde o registo.

Fico a aguardar uma ajuda vossa, obrigado. 👍

Abraço!

Edited by thoga31
GeSHi
Posted

daniel_silva,

Tens aí uma coisa interessante: um bug a esconder outro bug.

Para começar, quando tentas eliminar um registo, não podes simplesmente definir esconder := true e escrever o registo novamente. Primeiro é necessário fazeres seek até à posição onde o registo começa e aí sim escrevê-lo, pois se não o fizeres estarás simplesmente a criar um duplicado do original, mas com esconder := true. Este é o primeiro bug.

O primeiro bug nunca foi detectado porque tens um outro bug: quando perguntas ao utilizador se quer eliminar o cliente, pedes para ele carregar na tecla E, mas o teu código apenas actua caso seja pressionada a tecla S.

Corrigindo o bug da tecla errada irás reparar que de cada vez que «eliminas» um registo ele na realidade está a ser duplicado, pois não estás a escrevê-lo em cima do seu original mas sim a criar uma cópia sua logo de seguida.

Experimenta 🙂

  • Vote 1
Posted (edited)

Para trabalhares com ficheiros de em Pascal tens que ter isto em mente:Imagina um apontador, quando queres ler ou escrever um registo o apontador tem de estar imediatamente antes do registo isto para quê? Para que quando mandas ler ou escrever ele vai fazê-lo no que estiver imediatamente a seguir, assim quando lê, por exemlo, o registo 5 ele irá ficar a apontar para o registo 6. Se quizeres alterar o registo 5 tens de fazer recuar o ponteiro. Para esse efeito as funções seek e filepos funcionam muito bem. Vou-te dar o exemplo para este caso, mas se queres "brincar" com elas é melhor estudá-las assim como o filesize.

Tenta isto:

Procedure eliminar_cliente(var fc:ficheiro_cliente);
var ee:total_dados; var eliminar:char; num_biC:string;
begin
 ..
  writeln;
  writeln ('- Carregue na tecla [E] para eliminar: ');
  readln (eliminar);
  if (eliminar = 's') or (eliminar = 'S') then
begin
  seek(fc,filepos(fp)-1);	//coloca-te na posição correcta para escrever o registo
  ee.cliente.esconder := true; {esconder o registo}
  write(fc,ee);
end;
  close(fc);
end;

Mais 2 pontos:

- Estuda a função readkey, vais ver que vai ser uma grande ajuda em vez do readln para ler só uma tecla.

- Se o utilizador colocar um nº de contribuinte que não existe como é que o programa se comporta?

Edited by passarito
Posted

Boa tarde.

@pwseo o segundo bug foi mesmo distracção minha. 😛 obrigado por me avisares! 👍

@passarito agradeço-te muito por me teres ajudado neste tópico! Cada vez gosto mais deste fórum por ter pessoas que estão sempre disponíveis para ajudar. 😉

Vou seguir o teu concelho de estudar a função readkey.

Quando o nº de contribuinte não existir meto uma mensagem de erro, ou pergunto ao utilizador se ele pretende registrar. 😁

Obrigado! 🙂

Abraço.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.