Algoritmos e Estruturas de Dados II ARQUIVOS Rodney Carneiro Arquivos Permitem o armazenamento permanente dos dados, ao contrário das variáveis, que eram armazenadas em memória principal; – Exemplos: informações bancárias, dados de uma companhia telefônica, um simples cadastro de clientes; Um arquivo é uma estrutura criada em disco, ou em uma unidade de armazenamento permanente; Arquivos Um arquivo é uma estrutura de dados formada por um conjunto de registros, que por sua vez, são possuem campos de informação; Um registro não ocupa uma posição fixa dentro de um arquivo, pois este não possui tamanho pré-estabelecido (tamanho variável) Arquivo Registros Disco Campos ... Campos Registros Campos ... Campos Registros ... Campos ... Campos Arquivos Então podemos enxergar um arquivo como uma coleção de registros, que por sua vez armazenam um conjunto de campos relacionados à um mesmo item de dado; Um mesmo arquivo pode ser manipulado por algoritmos diferentes. Desta forma, um arquivo pode ser aberto por diferentes programas, desde que os mesmos estejam preparados para isto; Estrutura Física de um Arquivo Quando um arquivo FILE é criado, o mesmo possui a seguinte estrutura: A posição física corresponde a um número que é gerado automaticamente no instante que uma informação qualquer é incluída no arquivo. Este número corresponde ao “Endereço” da informação no arquivo, sendo que é através deste Endereço que é possível recuperar qualquer informação, sem precisar percorrer todo o arquivo em busca da mesma, ao invés disto basta fornecer o número da posição física da informação no arquivo. Arquivos A primeira coisa que deve ser feita para se criar um arquivo, é declará-lo. E para isto, é preciso definir de que tipo são os registros que ele armazenará; Exemplo: – Criação de um arquivo para armazenar informações de clientes (nome, telefone, endereço e cidade); Type cliente = record codigo : integer; nome : string[20]; telefone : string[14]; endereco : string[30]; cidade : string[20]; end; Var aux: cliente; arq_nome: file of cliente; Arquivos Depois da criação de um arquivo, ele pode ser utilizado de duas formas: – O arquivo pode ser consultado, fornecendo informações previamente gravadas nele (leitura); – O arquivo pode ser acrescido de novas informações (escrita ou gravação); Os algoritmos básicos envolvidos nestas duas circunstâncias são: Consultar arquivo Abrir arquivo Achar item procurado Copiar informações Fechar arquivo 1 2 3 4 Acrescentar arquivo Abrir arquivo Achar posição da inserção Gravar informações Fechar arquivo Arquivos Antes de realizar qualquer operação sobre um arquivo, é necessário criar um identificador para o mesmo; Isto feito, as ações passarão a ser direcionadas ao arquivo a partir deste identificador; Na linguagem Pascal, o comando que associa um identificador à um arquivo físico é o assign, e ele pode ser usado da seguinte forma: assign(arq_nome,‘C:\dados.dat'); Onde arq_nome é o identificador, e o segundo parâmetro é o nome físico do arquivo que será manipulado. Rotina : ASSIGN( ) Função : Serve para associar um determinado Nome de arquivo, no disco ou disquete com o arquivo definido pelo programador. Sintaxe : ASSIGN(Meu_Arquivo, STRING_Com_Nome_Arquivo_DOS). Exemplo: PROGRAM TESTE; TYPE Registro = RECORD Codigo : INTEGER; Nome : STRING; Salario : REAL; END; VAR Arq_nome : FILE OF Registro; BEGIN ASSIGN (Arq_nome, ’c:\dados.dat’); END. Onde: Arq_nome Nome Lógico do arquivo (aquele que será referenciado pelo programador na construção do seu código fonte C:\ Diretório, ou caminho onde será armazenado o arquivo no disco dados.dat Nome físico do arquivo que será manipulado Arquivos Abrindo um arquivo: é sempre necessário abrir um arquivo para que se possa adicionar ou ler informações no/do mesmo; Existem três formas de se abrir um arquivo: – rewrite; – reset; – append; (somente p/ texto) Sintaxe: – Abrir um arquivo novo (inicializar); Procedure Abrir; Begin assign(arq_nome,‘c:\dados.dat'); rewrite (arq_nome); End; – Na linguagem Pascal, o comando rewrite é utilizado para abrir um arquivo inicializando-o. Com o uso deste comando, se o arquivo não existir, o Turbo Pascal irá criá-lo. Se existir, seu conteúdo será destruído. Rotina : REWRITE( ) Função : Cria e abre para E\S um arquivo. Caso o arquivo não exista, o mesmo será criado. Caso o arquivo já exista, todos os dados existentes nele serão apagados. Sintaxe : REWRITE(Meu_Arquivo); Exemplo: PROGRAM Teste; TYPE Registro = RECORD Codigo : INTEGER; Nome : STRING; Salario : REAL; END; VAR Arq_nome : FILE OF Registro; BEGIN ASSIGN (Arq_nome, ’c:\dados.dat’); REWRITE (Arq_nome); END. Arquivos Abrir um arquivo já existente, sem destruir seu conteúdo; – Na linguagem Pascal, o comando reset é utilizado para abrir um arquivo preservando seu conteúdo pré-existente. Este comando é utilizado, principalmente, para abrir um arquivo para a leitura, pois ele posiciona o ponteiro do arquivo no primeiro registro gravado no mesmo. • Uma tentativa de abrir um arquivo não existente com reset pode provocar um erro de E/S. Para solucionar isto, deve-se desativar a diretiva I do compilador com o comando {$I-}. Procedure Abrir; Begin assign(arq_nome,‘c:\dados.dat'); reset (arq_nome); End; Rotina : RESET( ) Função : Abre para E/S um arquivo que já exista. Caso o arquivo não exista ocorrerá um erro de execução e o programa será abortado. Sintaxe : RESET(Meu_Arquivo); Exemplo: PROGRAM Teste; TYPE Registro = RECORD Codigo : INTEGER; Nome : STRING; Salario : REAL; END; VAR Arq_nome : FILE OF Registro; BEGIN ASSIGN (Arq_nome, ’c:\dados.dat’); RESET (Arq_nome); END. Arquivos Abrir um arquivo texto já existente, sem destruir seu conteúdo, preparando-o para gravar informações; – Na linguagem Pascal, o comando append é utilizado para abrir um arquivo preservando seu conteúdo pré-existente. Este comando é utilizado, principalmente, para abrir um arquivo para a gravação de dados, pois ele posiciona o ponteiro no final do arquivo. Procedure Abrir; Begin assign(arq_nome,‘c:\dados.dat'); append (arq_nome); End; Arquivos Fechando um arquivo: é sempre necessário fechar um arquivo após o seu uso, para não deixar o seu conteúdo exposto e nem comprometer a sua integridade; Depois de fechado um arquivo, para utilizá-lo novamente basta abrí-lo (com rewrite, reset, ou append). Não é necessário associá-lo novamente a um arquivo físico com o comando assign; Sintaxe: Procedure Fechar; – Fechar um arquivo; Begin close (arq_nome); End; Rotina : CLOSE( ) Função : Fecha um arquivo que tenha sido aberto com RESET\REWRITE. Sintaxe : CLSE(Meu_Arquivo); Exemplo: PROGRAM Teste; TYPE Registro = RECORD Codigo : INTEGER; Nome : STRING; Salario : REAL; END; VAR Arq_nome : FILE OF Registro; BEGIN ASSIGN (Arq_nome, ’c:\dados.dat’); RESET (Arq_nome); CLOSE(Arq_nome) END. Rotina : WRITE( ) Função : A Rotina WRITE tem a mesma Função de saída de informações como até agora já tínhamos trabalhado, somente que ao invés da informação ser apresentada no vídeo, a mesma será armazenada em um arquivo. Sintaxe : WRITE (Meu_Arquivo, Registro) Exemplo: PROGRAM Teste; TYPE Registro = RECORD Codigo : INTEGER; Nome : STRING; Salario : REAL; END; VAR Arq_Nome : FILE OF Registro; Reg : Registro; BEGIN ASSIGN (Arq_nome ‘C:\Dados.Dat’); REWRITE (Arq_nome); CLRSCR; WRITE (‘Digite o Codigo: ‘); READLN (Reg.Codigo); WRITE (‘Digite o Nome: ‘); READLN (Reg.Nome); WRITE (‘Digite o Salario: ‘); READ LN(Reg.Salario); WRITE (Arq_nome, Reg); CLOSE (Arq_nome); END. Rotina : READ( ) Função : A Rotina READ tem a mesma Função de entrada de informações como até agora já tínhamos trabalhado, somente que ao invés da leitura ser feita pelo teclado, a mesma será feita de um arquivo. Sintaxe : READ (Meu_Arquivo, Registro) Exemplo: PROGRAM Teste; TYPE Registro = RECORD Codigo : INTEGER; Nome : STRING; Salario : REAL; END; VAR Arq_nome : FILE OF Registro; Reg : Registro; BEGIN ASSIGN (Arq_nome, ‘C:\Dados.Dat’); RESET (Arq_nome); READ (Arq_nome, Reg); CLRSCR; WRITELN (‘Codigo = ‘, Reg.Codigo); WRITE LN(‘Nome = ‘, Reg.Nome); WRITELN(‘Salario = ‘,Reg.Salario:0:2); CLOSE (Arq_nome); END. Observação: Após cada operação READ/WRITE no arquivo, o endereço do registro corrente no arquivo é incrementado em uma unidade. Assim por Exemplo, se o endereço do registro corrente é igual a 10, após uma operação de READ/WRITE, o registro corrente passará a ser o número 11. Rotina : FILEPOS( ) Função : Retorna um número inteiro indicando qual o registro corrente em um arquivo. Sintaxe : Registro_Corrente : = FILEPOS (Meu_Arquivo) Exemplo: PROGRAM Teste; TYPE Registro = RECORD Codigo : INTEGER; Nome : STRING; Salario : REAL; END; VAR Arq_nome : FILE OF Registro; Corrente : INTEGER; BEGIN ASSIGN (Arq_nome, ‘C:\Dados.Dat’); RESET (Arq_nome); Corrente : = FILEPOS(Arq_nome); CLRSCR; WRITELN(Corrente); CLOSE (Arq_nome); END. Rotina : FILESIZE( ) Função : Retorna quantos registro existem armazenados no arquivo. Sintaxe : Tamanho_Arquivo : = FILESIZE (Meu_Arquivo) Exemplo: PROGRAM Teste; TYPE Registro = RECORD Codigo : INTEGER; Nome : STRING; Salario : REAL; END; VAR Arq_nome : FILE OF Registro; Total_reg : INTEGER; BEGIN ASSIGN (Arq_nome, ‘C:\Dados.Dat’); RESET (Arq_nome); Total_reg : = FILESIZE (Arq_nome); CLRSCR; WRITELN (Total_reg); CLOSE (Arq_nome); END. Arquivos Outros comandos para a manipulação de arquivo: – Seek(F,P); • Move o ponteiro do arquivo F para o início do número de registro P; – EOF(F); • Retorna verdadeiro se o ponteiro do arquivo F estiver posicionado no final (último registro); Rotina : SEEK( ) Função : Posiciona o ponteiro do arquivo em um registro determinado, para que o mesmo possa ser processado. Sintaxe : SEEK(Meu_Arquivo, Endereço_Registro) Exemplo: PROGRAM Teste; TYPE Registro = RECORD Codigo : INTEGER; Nome : STRING; Salario : REAL; END; VAR Arq_nome : FILE OF Registro; Reg : Registro; BEGIN ASSIGN (Arq_nome, ‘c:\Dados.Dat’); RESET (Arq_nome); SEEK (Arq_nome, 10); READ (Arq_nome Reg); CLRSCR; WRITELN(‘Codigo = ‘, Reg.Codigo); WRITELN (‘Nome = ‘, Reg.Nome); WRITELN (‘Salario = ‘, Reg.Salario:0:2); CLOSE (Arq_nome); END. Observação: O Comando SEEK, posicionará o cursor (Indicador de Registro) no registro fisico número 10; Rotina : EOF( ) Função : Esta é uma função Booleana, que Retorna TRUE caso se alcance o final do arquivo, FALSE caso contrário. Sintaxe : Chegou_Final : = EOF (Meu_Arquivo) Exemplo: PROGRAM Teste; USES CRT; TYPE Registro = RECORD Codigo : INTEGER; Nome : STRING; Salario : REAL; END; VAR Arq_nome : FILE OF Registro; Reg : Registro; BEGIN ASSIGN (Arq_nome, ‘C:\Dados.Dat’); RESET (Arq_nome); WHILE NOT EOF(Arq_nome) DO BEGIN READ (Arq_nome, Reg); CLRSCR; WRITELN(‘Codigo = ‘,Reg.Codigo); WRITELN(‘Nome = ‘, Reg.Nome); WRITE LN(‘Salario = ‘, Reg.Salario:0:2); READKEY; END; CLOSE (Arq_nome); END. Observação: Neste exemplo será realizado a leitura do primeiro registro do arquivo até o final do arquivo, apresentando cada registro na tela; A instrução WHILE NOT EOF(Arq_nome) DO quer dizer, Faça enquanto NAO FOR O FINAL DO ARQUIVO. Diretivas de Erros Pascal O Turbo Pascal possui diretivas de compilação para ativação/desativação da verificação automática de erros, permitindo que o código do erro possa ser identificado com a função IOResult. {$I-} {$I+} Desativa a verificação automática de erros Ativa a verificação automática de erros Quando for utilizada a diretiva {$I-}, o programa não será abortado quando uma operação de Entrada/Saída não for bem sucedida. Se a operação for bem sucedida a função IOResult retorna 0, do contrário retorna o código do erro (Ver exemplo a seguir). Controlar a Abertura de um Arquivo Rotina para abertura de arquivo: Procedure abre_arq (nome: string); Begin Assign (arq_nome, ‘c:\dados.dat’); {$I-} Reset (arq_nome); {$I+} If Ioresult <>0 then begin Rewrite (arq_nome); end; End; OBSERVAÇAO: A variável IORESULT é uma variável de ambiente, ela armazena o código do erro, após uma operação em um Arquivo Pascal; Se IORESULT for igual a Zero quer dizer que nao deu erro, qualquer valor Diferente de Zero, representa um erro que deve ser consultada na tabela de erros do PASCAL Algoritmos e Estruturas de Dados II ARQUIVOS Rodney Carneiro