Ir ao conteúdo
  • Cadastre-se

Pascal/Delphi Mudando informação em file


Posts recomendados

Olá, gostaria de saber a melhor forma para se alterar um DADO que ja foi escrito dentro de uma file em pascal.

Sei da forma de "criar" um arquivo temporario e trocar as informações assim também realizando a troca do dado necessario.

Porém gostaria de saber se há uma forma mais eficiente de realizar essa função, agradeço.

Link para o comentário
Compartilhar em outros sites

  • Membro VIP
 

Olá, gostaria de saber a melhor forma para se alterar um DADO que ja foi escrito dentro de uma file em pascal.

Sei da forma de "criar" um arquivo temporario e trocar as informações assim também realizando a troca do dado necessario.

Porém gostaria de saber se há uma forma mais eficiente de realizar essa função, agradeço.

 

 

em arquivos binário e possível, basta posicionar o ponteiro do arquivo com seek e gravar por cima (não funciona com arquivos de texto, porque são sequencias). 

 

Supondo que acabou de ler a posição que quer alterar, basta reposicionar na posição anterior.

Seek(f, FilePos(f)-1);

 

Se for baseado nesse programa, talvez funcione com algo do tipo:

Seek(arquivo, numeroMatricula);

 

 

Link para o comentário
Compartilhar em outros sites

@Simon Viegas

Cara, agradeço a ideia e executei da seguinte forma.

E por incrivel que pareça funcionou, o problema é que ele não substitui a informação anterior, ele duplica. Ou seja

ficam duas matriculas 1, uma com o nome anterior e outra com o nome bugado.

Por exemplo:

Se eu substituir o nome:

Matricula: 1 

Nome: Antonio

 

Para

 

Matricula: 1 

Nome: Neto

 

Vão ficar duas matriculas

Uma com nome antonio

e outra com nome Netonio. kkk

{$I-} reset(arquivo); {$I+};
						  if ioresult <> 0 then
							  begin
							    writeln;
							    write(' Nada encontrado no arquivo!');
							    delay(1000);
							  end
						  else
							  begin
							seek(arquivo, 0);
						while not eof(arquivo) do
							  begin
							    read(arquivo, fu);
							    if fu.matricula = busca then
							  	begin
								  	clrscr;
								  	gotoxy(15,15); write('Digite o Novo Nome: ' );
								  	gotoxy(35,15); Read(fu.nome);
								  	Seek(arquivo, busca+1);
								  	write(arquivo, fu);
								  	
							  	end;
								end;
								close(arquivo);
							end;
						end;

 

Link para o comentário
Compartilhar em outros sites

  • Membro VIP

Olá.

 

 

@Simon Viegas

Cara, agradeço a ideia e executei da seguinte forma.

E por incrivel que pareça funcionou

 

Ué!? a ideia era que funcione mesmo... 😂

 

 

 

 

o problema é que ele não substitui a informação anterior, ele duplica. Ou seja

ficam duas matriculas 1, uma com o nome anterior e outra com o nome bugado.

Por exemplo:

Se eu substituir o nome:

Matricula: 1 

Nome: Antonio

 

Para

 

Matricula: 1 

Nome: Neto

 

Vão ficar duas matriculas

Uma com nome antonio

e outra com nome Netonio. kkk

 

Chegou analisar como ficou os outros registros? parou para analisar qual comportamento está ocorrendo? então, peguei o seu código e reorganizei. Nele mesmo deixei o comentário do possível problema:

 

{$I-} Reset(arquivo); {$I+};
if IOResult() <> 0 then
  begin
  writeln;
  {write(' Nada encontrado no arquivo!');}
  write(' Ocorreu algum erro ao tentar abrir o arquivo');
  Delay(1000);
  end
else
  begin
  {Seek(arquivo, 0);} //o Reset() já faz isso
  while not eof(arquivo) do
    begin
    read(arquivo, fu);
    if fu.matricula = busca then
      begin
      ClrScr;
      GotoXY(15,15); write('Digite o Novo Nome: ');
      {GotoXY(35,15); read(fu.nome);} 
      GotoXY(35,15); readln(fu.nome);}
      Seek(arquivo, busca+1); //<-- ajuste aqui. Provavelmente não tem esse "+1"                   
      write(arquivo, fu);
      end;
  end;
  Close(arquivo);
  end;
end;

 

Outra forma seria como citado:

 

Seek(arquivo, FilePos(arquivo)-1);

 

Ou seja: quando você ler o registro no arquivo, o ponteiro vai está apontando para o próximo registro. Se ler mais uma linha, vai ler os dados da matrícula posterior ao que você achou. Se escrever, da mesma forma: vai escrever em cima da posição posterior ao que você achou. Como você quer posicionar na mesma posição que você achou, basta posicionar um registro atrás da posição atual, assim como citado acima.

 

 

RESUMINDO:

Tanto para achar o registro, tanto para reescrever, basta utilizar o número da matrícula no Seek().

 

Se as matrículas estão de acordo com as posições (e vice-versa), então NÃO precisa fazer comparações. Apenas posicione o ponteiro do arquivo. Algo como citado na minha postagem anterior:

 

 

Seek(arquivo, busca);

 

O mesmo comando é utilizado para reposicionar para substituir!

 

Obs.: como (acho eu, não lembro), o Seek() cria posições quando elas não existem, na hora de posicionar para ler, seria bom criar uma camada de proteção. Algo como:

if (busca > 0) and (busca <= FileSize(arquivo)) then 
  begin
  Seek(arquivo, busca);
  read(arquivo, fu);  
  end;

 

 

 

ADENDO:

  • Remova a tabulação do seu código, ou seja: utilize apenas espaços e vez de "tab". A depender do editor, nas configurações deve ter algum lugar que "substitui a tabulação por espaço", no caso, ao pressionar tab, vai inserir "2 ou 3 espaços", em vez de inserir a tabulação. Se não tiver ou não encontrar, utilizar a barra de espaços mesmo. Evite o "tab".
  • Assim como o Reset(), Close(), Erase(), o Seek() também pode dar erro de IO, logo, também precisaria das diretivas {I-} e {I+}, e no caso, do IOResult() para tratar o código de resposta. Nesse link tem uma relação de códigos. Geralmente apenas verificamos se foi <> 0 ou não, mas acho que ficaria bacana o programa tratar de outros erros (ou mesmo todos).


Qualquer coisa tenta ajustar, e após poste o código completo para reanalisarmos.
 

No aguardo.

Link para o comentário
Compartilhar em outros sites

@Simon Viegas Eu entendi essa adendo, e agradeço MUITO você estar ajudando o novato aqui.

Dicas muito boas da sua parte.

Porém o que quis dizer é

Ainda que eu use (seek, busca);

 

Se o dado inserido for menor que o anterior, ele não cobre a informação inteira.

 

Por exemplo o Nome que eu mudo de Antonio para Neto

 

E fica Netonio.

 

no caso do (seek, fu.matricula+1);

é porque eu queria alterar a casa fu.nome, porém seek só aceita integer, então eu busco pela matricula e adiciono uma casa para ir para a linha do nome.

adicionado 26 minutos depois
26 minutos atrás, TheMajor disse:

@Simon Viegas Eu entendi essa adendo, e agradeço MUITO você estar ajudando o novato aqui.

Dicas muito boas da sua parte.

Porém o que quis dizer é

Ainda que eu use (seek, busca);

 

Se o dado inserido for menor que o anterior, ele não cobre a informação inteira.

 

Por exemplo o Nome que eu mudo de Antonio para Neto

 

E fica Netonio.

 

no caso do (seek, fu.matricula+1);

é porque eu queria alterar a casa fu.nome, porém seek só aceita integer, então eu busco pela matricula e adiciono uma casa para ir para a linha do nome.

Outra coisa, sempre que altero ele cria um novo cadastro, como se fosse uma nova matricula e copia todos os dados.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

  • Membro VIP
1 hora atrás, TheMajor disse:

@Simon Viegas Eu entendi essa adendo, e agradeço MUITO você estar ajudando o novato aqui.

Dicas muito boas da sua parte.

Porém o que quis dizer é

Ainda que eu use (seek, busca);

 

Se o dado inserido for menor que o anterior, ele não cobre a informação inteira.

 

Por exemplo o Nome que eu mudo de Antonio para Neto

 

E fica Netonio.

 

Viuge... talvez possa está relacionado ao "ln" do uso de read X readln em algum ponto. Ou pode ser como funciona a estrutura binária dos registros no arquivo. Só analisando com mais calma para tentar entender e sugeri um contorno.

 

Suspeito que seja aqui:

1 hora atrás, Simon Viegas disse:

      GotoXY(15,15); write('Digite o Novo Nome: ');
      {GotoXY(35,15); read(fu.nome);} //perceba como desativei essa linha, ou seja: "deve" utiliza readln()
      GotoXY(35,15); readln(fu.nome);}

 

Testa aí usando readln() pra ver.

 

Testa também utilizando writeln() para escrever no arquivo. Não sei dizer. Algo assim:

 

1 hora atrás, Simon Viegas disse:

writeln(arquivo, fu);

 

 

Obs. 1: para efeito práticos, faça TODA LEITURA DADOS DO TECLADO usando se readln(). O read() é só usando em casos específicos (e mais avançados). Para leitura do arquivo binários eu acho que só funciona com read() mesmo. Mas se não funcionar nas tentativas anteriores, tente usar readln() para ler do arquivo.

 

 

 

 

 

1 hora atrás, TheMajor disse:

no caso do (seek, fu.matricula+1);

é porque eu queria alterar a casa fu.nome, porém seek só aceita integer, então eu busco pela matricula e adiciono uma casa para ir para a linha do nome.

 

Então, o arquivo trabalha com registros completos. Quando faz uma atualização, está atualizando todo o registro. O Seek() serve para apontar para a posição do registro, e não para posição do dado do registro.

 

Tento a posição do registro, você dá um Seek() para essa posição. Ler os dados.. terá o registro completo. Aí vai e muda o nome desse registro (na memória). Dar um novo Seek() para posição que quer escrever no arquivo (na própria posição que leu) e escreve (o registro). Todas os dados do registro serão alterados.

 

Outra observação importante: para o Pascal NÃO existe relação entre a matrícula e a posição. Isso é uma "abstração" de quem desenvolveu a lógica do programa, ou seja: não faz sentido tentar dar um Seek() pelo nome... por exemplo: se fosse algum outro atributo do tipo integer, como uma idade, não iria funcionar da mesma forma. Apenas ocorreu que foi programado uma lógica em que a matrícula do aluno seria justamente a posição dele no arquivo... assim servindo para alguns aspectos como: "não repetir número de matrícula" (2 registros não podem fica na mesma posição) e "poder achar facilmente o registro no arquivo" (a posição do registro na matrícula é o próprio número da matrícula) já que tem a posição lá.

 

 

Outro exemplo de abstração. A matrícula poderia ser assim:

2019.01.ajf.010

No caso, deixei o 3 últimos dígito como um "código interno" que significa a posição dele no arquivo. Os outros campos a esquerda poderia significar outras coisas, como ano e semestre mais outro coisa qualquer. Aí, quando fosse buscar essa matrícula no arquivo, "copiaria os 3 últimos caracteres da string" e converteria para número. Depois buscaria o resultado no arquivo. Algo como:

matricula := '2019.01.ajf.010'
pos := PegaPosicaoPelaMatricula(matricula); //A funcao vai retornar o integer 010 (no caso 10)
Seek(arquivo, pos); //posiciona na posição do registro dessa matrícula

Entende?

 

É uma abstração.. apenas percebemos como cada funciona funciona e criamos relações (na "nossa cabeça") entre uma coisa e outra.

 

 

@TheMajor, tente fazer os ajustes. Depois poste o código completo para reanalisarmos. Se tiver dúvida em alguma parte, é só postar também.

 

No aguardo.

adicionado 10 minutos depois

PS:
Se estivesse trabalhando com funções e oricedunebti. Veja uma exemplo:

matriculaBusca := '2019.01.ajf.010' //aa matrícula que quero alterar o nome
registroArquivo := retornarRegistroArquivo(arquivo, matriculaBusca); //pego o registro do arquivo pela matrícula
registroArquivo.nome := 'Antorio'; //mudei o nome
escreverRegistroArquivo(arquivo, registroArquivo); //escreve o registro no arquivo

 

O retornaRegistroArquivo() seria implementado de forma que conseguisse extrair a posição (poderia usar o PegaPosicaoPelaMatricula()) e pegar o registro do arquivo.

 

E o escreverRegisroArquivo(), resumidamente, conseguiria escrever ("reescrever") o registro na posição correta.

 

Por ai vai.

Link para o comentário
Compartilhar em outros sites

@Simon Viegas

 

aparentemente consegui resolver da seguinte forma

Eu coloquei esse procedure no começo do codigo, para ele pegar as variaveis sempre limpas.

E fiz isso, aparentemente funcionou, vamos ver mais pra frente se da outros erros.

	begin
	 gotoxy(30,28); read(op);
	 case op of
	 	1:begin
	 			clrscr;
	 				gotoxy(15,15); write('Digite o novo nome: ');
	 				readln(fu.nome);
	 			assign(arquivo, 'C:\tete\armazem.dat');
						reset(arquivo);
	 				rewrite(arquivo);
	 			 seek(arquivo, matr);
	 				write(arquivo, fu);
						close(arquivo);
							delay(1000); 
	 			
	 		end;
	 	end;
		end;

image.png.6dd2aea8f851c3f99ee93e22484cb043.png

Link para o comentário
Compartilhar em outros sites

  • Membro VIP
4 minutos atrás, TheMajor disse:

@Simon Viegas PascalZIM, indicaram como o melhor para iniciantes. 

 

Pronto. Com o seu código aberto, pressione CTRL+I para identar o seu código. É muito importante sempre manter o código identado.

 

 

12 minutos atrás, TheMajor disse:

aparentemente consegui resolver da seguinte forma

Eu coloquei esse procedure no começo do codigo, para ele pegar as variaveis sempre limpas.

E fiz isso, aparentemente funcionou, vamos ver mais pra frente se da outros erros.


Acho que não é isso.

 

 

Segue abaixo alguma observações sobre o seu código atual:

begin
{GotoXY(30,28); read(op);} //Não use read, utilize apenas readln para ler do teclado
GotoXY(30,28); readln(op);
case op of
  1:begin
    ClrScr;
    GotoXY(15,15); write('Digite o novo nome: '); readln(fu.nome);
    {assign(arquivo, 'C:\tete\armazem.dat');} //Nâo precisa, o arquivo assinalado uma única vez no início
    {reset(arquivo);} //Nâo precisa, o arquivo já deveria está aberto E não precisa posicionar no início
    {rewrite(arquivo);} //Não precisa, ou melhor, NÃO DEVE SER UTILIZADO. Esse comando recria o arquivo
    Seek(arquivo, matr); //Qual o valor de matr nesse momento?
    write(arquivo, fu); //O registro fu está com os outros dados do resgistro?
    Close(arquivo); //Não precisa fechar, o arquivo fica aberto enquanto está com o programa aberto
    Delay(1000); 
    end;
  end; //fim case
end;

 

 

 

Resumidamente você precisa fazer isso:

- ler o registro do arquivo na posição correta;

- alterar o nome (na variável de registro que você acabou de ler);

- escrever o arquivo na posição correta.

 

@TheMajor, tente alterar e poste o código completo. Obs.: antes de copiar o código, pression CTRL+I para identar. E não user tab, só barra de espaço, ok?

 

No aguardo.

Link para o comentário
Compartilhar em outros sites

  • Membro VIP
1 minuto atrás, TheMajor disse:

@Simon Viegas Justamente, eu uso o rewrite para recriar o registro, assim eliminando o 2 registro que ele cria forçadamente, jaja posto o codigo.

 

O ReWrite() serve para recriar o ARQUIVO. Ele cria (ou recria) um arquivo novo.

 

Veja:

 

- existe os dados (atributos), exemplo:

matricula:integer;
nome:string[50];
cpf:string;
rg:integer;
titulo:integer;
cnh:String;
cep:integer;
endereco:string;
bairro:string;
cidade:string;
pais:string;
sexo:char;
uf:string[2];
estadocivil:string;
email:string;
telefone:integer;
dataa:integer;
datad:integer;
status:string;

 

- para facilitar a organização e o acesso a cada um deles, podem-se criar um registro, exemplo:

type
  t_funcionario = record
    matricula:integer;
    nome:string[50];
    cpf:string;
    rg:integer;
    titulo:integer;
    cnh:String;
    cep:integer;
    endereco:string;
    bairro:string;
    cidade:string;
    pais:string;
    sexo:char;
    uf:string[2];
    estadocivil:string;
    email:string;
    telefone:integer;
    dataa:integer;
    datad:integer;
    status:string;
  end;
  
var
  funcionario :t_funcionario;

Ou seja, agrupa os atributos. Fica muito mais fácil acessar cada atributo de um mesmo funcionário...

 

 

- Para "persistir" os dados após o programa ser finalizado, podem-se utilizar arquivos. Ex.:

arqFuncionarios: file of t_funcionario;

Nesse caso, se não existissem os record, precisaria de um arquivo para cada atributo. Imagina a trabalheira e a bagunça? O arquivo binário (quando utiliza esse file) trabalha com a estrutura dos registros por completo.

 

 

Então, o comando ReWrite() atua no arquivo ("no HD"), e não registro ("na memória RAM"). Vai "zerar" o arquivo que você criou justamente para guardar os dados.

adicionado 4 minutos depois

ADENDO:

As variáveis lá no var poderiam ser declaradas assim:

var
  funcionario :record
                 matricula:integer;
                 nome:string[50];
                 cpf:string;
                 rg:integer;
                 titulo:integer;
                 cnh:String;
                 cep:integer;
                 endereco:string;
                 bairro:string;
                 cidade:string;
                 pais:string;
                 sexo:char;
                 uf:string[2];
                 estadocivil:string;
                 email:string;
                 telefone:integer;
                 dataa:integer;
                 datad:integer;
                 status:string;
               end;

 

Ou seja, utilizar type (ou não) vem também para facilitar/organizar o processo, pois com ele você conseguirá mais facilmente definir o tipo da variável e do arquivo (usará t_funcionario que é justamente o uma "referencia" ao record).

adicionado 7 minutos depois

Entende? é uma conjuntos de recursos que são combinados e utilizado se forma a fazer que a execução do algoritmo faça o programa se comportar da forma que deseja.

 

- record;

- type;

- file of;

- if;

- writeln;

- GotoXY;

etc

 

Cada um independente do outro, mas que podem sem combinados de acordo com a sintaxe do Pascal.

Link para o comentário
Compartilhar em outros sites

@Simon Viegas  Conclusão que cheguei:

clrscr;
      gotoxy(15,15); write('Digite o novo nome: ');
      readln(Nome);
      assign(arquivo, 'C:\tete\armazem.dat');
      {$I-} reset(arquivo); {$I+};
      if ioresult = 0 then
      begin
        assign(novo, 'C:\tete\temp.dat');
        {$I-} rewrite(novo); {$I+};
        if ioresult = 0 then
        begin
          seek(arquivo, 0);
          while not eof(arquivo) do
          begin
            read(arquivo, contatoTemporario);
            if matr = contatoTemporario.matricula then
            begin
              contatoTemporario.nome := Nome;
              encontrado := true;
              write(novo, contatoTemporario);
            end
            else
            write(novo, contatoTemporario);
          end;
          close(arquivo);
          close(novo);
          erase(arquivo);
          rename(novo, 'C:\tete\armazem.dat');
        end;
      end;
    end;

 

Link para o comentário
Compartilhar em outros sites

  • Membro VIP

Vou tentar ser mais objetivo:

 

Tente seguir essa lógica abaixo:

 

Orientações para alterar o nome de um registro no arquivo

 

Obs.: O ARQUIVO JÁ ESTÁ ASSINALADO E ABERTO. Não precisa fazer novamente.

 

- Obtenha o número da matrícula;

- Posicione o arquivo na posição correspondente da matrícula;

- Leia o registro do arquivo;

- Altere o nome nome desse registro;

- Posicione novamente o arquivo na posição correspondente da matrícula;

- Escreva o registro no arquivo.

 

Só isso. :)

 

 

 

Faça exatamente dessa forma.

Caso não consiga, informa o que ocorreu.

Caso tenha dúvidas sobre alguma parte, é só dizer. NÃO TENTE FAZER DE OUTRA FORMA, beleza?

 

No aguardo

Link para o comentário
Compartilhar em outros sites

@Simon Viegas Se eu entendi a lógica é mais ou menos essa:

      begin 
		clrscr;
       gotoxy(15,15); write('Digite a nova informação: ');
       readln(num);
       reset(arquivo);
       seek(arquivo, matr);
       read(fu.cnh);
       fu.cnh:=test;
       seek(arquivo, matr);
       write(arquivo, test);
      end;

Mas da erro, pois write só aceita se for Fu.

adicionado 1 minuto depois
1 minuto atrás, TheMajor disse:

@Simon Viegas Outra tentativa falha:


    5:begin
       clrscr;
       gotoxy(15,15); write('Digite a nova informação: ');
       readln(test);
       reset(arquivo);
       seek(arquivo, matr);
       read(fu.cnh);
       fu.cnh:=test;
       seek(arquivo, matr);
       write(arquivo, fu.cnh); 
     end;  
    end;
  end;

 

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

  • Membro VIP
3 minutos atrás, TheMajor disse:

Mas da erro, pois write só aceita se for Fu.

 

Exatamente*. E porque está passando teste?

 

* você pode utilizar qualquer variável que seja do mesmo tipo que o arquivo, o seja: do tipo funcionario.

adicionado 1 minuto depois

Os passos são esses:

1 hora atrás, Simon Viegas disse:

Obs.: O ARQUIVO JÁ ESTÁ ASSINALADO E ABERTO. Não precisa fazer novamente.

- Obtenha o número da matrícula;

- Posicione o arquivo na posição correspondente da matrícula;

- Leia o registro do arquivo;

- Altere o nome desse registro;

- Posicione novamente o arquivo na posição correspondente da matrícula;

- Escreva o registro no arquivo. 

 

Está com dúvidas em qual parte?

Link para o comentário
Compartilhar em outros sites

@Simon ViegasEsse código é a opção 5, após o usuario digitar a matricula (salva em matr); ele vai para essa tela onde tecnicamente deveria executar a mudança. deveria mudar o campo "CNH" do usuario.

       clrscr;
       gotoxy(15,15); write('Digite a nova informação: ');
       readln(fun.cnh);
       reset(arquivo);
       seek(arquivo, matr);
       read(arquivo, fu);
       fu.cnh:=fun.cnh;
       seek(arquivo, matr);
       write(arquivo, fun);
			 close(arquivo);
			 clrscr;
			 gotoxy(15,15); Write('Tudo certo');
			 delay(200);
			 tela;

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

  • Membro VIP

Qual erro está dando agora?

11 minutos atrás, TheMajor disse:

Quando você diz ALTERE O NOME DESSE REGISTRO, altero pra que então?

 

Eu estava tratando como se quisesse alterar o nome. Com essa lógica, você pode trocar qualquer dado do registro...

 

e aí, funcionou?

Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...