A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

10 Novembro 2006Leitura, Escrita e Processamento de Registos - Estruturas e Listas 1 Leitura, Escrita e Processamento de Registos Estruturas e Listas Jorge.

Apresentações semelhantes


Apresentação em tema: "10 Novembro 2006Leitura, Escrita e Processamento de Registos - Estruturas e Listas 1 Leitura, Escrita e Processamento de Registos Estruturas e Listas Jorge."— Transcrição da apresentação:

1 10 Novembro 2006Leitura, Escrita e Processamento de Registos - Estruturas e Listas 1 Leitura, Escrita e Processamento de Registos Estruturas e Listas Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2006/2007

2 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 2 Registos em Ficheiros Muita informação alfanumérica está armazenada em ficheiros, na forma de registos. Por exemplo, numa base de dados de uma empresa, são mantidos ficheiros com informação sobre os empregados da empresa. Muitas aplicações (de gestão) consistem em ler ficheiros e criar outros com a informação devidamente processada. Por exemplo: ler um ficheiro de empregados e escrever outro, apenas com os empregados com vencimento superior a 1000.

3 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 3 Leitura de Ficheiros A primeira questão a resolver consiste no tratamento dos caracteres brancos em cadeias de caracteres. Isto porque há duas formas típicas de armazenamento dessas cadeias: –Comprimento Fixo: As cadeias têm sempre o mesmo número de caracteres (sendo usados espaços se necessário); –Comprimento Variável: As cadeias têm o número de caracteres necessários, sendo necessários caracteres separadores, tipicamente tabs (horizontais).

4 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 4 Leitura de Ficheiros Por exemplo, Pedro Vieira pode ser codificado –Comprimento Fixo: Com 5+1+6 = 12 caracteres (incluindo o espaço), mais 13 espaços, para permitir cadeias de comprimento 25, que podem armazenar nomes com até 25 caracteres (incluindo espaços); –Comprimento Variável: Apenas com os 12 caracteres necessários, sendo separado do vencimento por um tab horozontal (\t).

5 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 5 Leitura de Ficheiros Em Octave (e em C) os dois tipos de codificação requerem instruções de leitura padronizada (com templates) diferentes. –Comprimento Fixo: Utiliza-se um template %nc em que n é o número de caracteres a ler; –Comprimento Variável: Utiliza-se um template %s; Neste último caso, levanta-se um problema: O template %s, não lê nem caracteres brancos nem espaços. Assim, o nome Pedro Vieira seria lido não como 1, mas sim como 2 cadeias. Em geral, ter-se-ia de conhecer o número de nomes (próprios, apelidos e partículas de ligação). Isto pode ser evitado com o uso de espaços especiais (non break spaces - ASCII 160), que são lidos como quaisquer outros caracteres, mas são impressos como espaços.

6 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 6 Leitura de Ficheiros Caso seja necessário, pode converter-se um ficheiro noutro, convertendo-se todos os espaços em espaços especiais, com a função abaixo: function x = rem_sp(f_in_name, f_out_name); [f_in, msg] = fopen(f_in_name, "r"); [f_aux,msg] = fopen(f_out_name, "w"); [ch, count] = fscanf(f_in,"%1c","C"); while !feof(f_in) if ch == " " ch = setstr(160); endif; fprintf(f_aux, "%1c", ch); [ch, count] = fscanf(f_in,"%1c","C"); endwhile; fclose(f_in); fclose(f_aux); endfunction;

7 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 7 Leitura de Ficheiros Comprimento Fixo: Cada linha do ficheiro, assumindo-se que um nome é guardado com 25 caracteres, pode ser lida com as seguintes instruções de leitura padronizada, fscanf: [cod, count] = fscanf(fid,"%i","C"); [nome, count] = fscanf(fid,"%25c","C"); [venc, count] = fscanf(fid,"%f","C"); [data, count] = fscanf(fid,"%s","C"); ou numa só instrução [cod,nome,venc,data,count]=fscanf(fid,"%i%25c%f%s","C"); 610Paulo Fernandes Lopes2341.3615/04/1996

8 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 8 Leitura de Ficheiros Comprimento Variável: Neste caso, quer o nome quer a data podem ser lidos com o template %s da instrução fscanf, podendo o registo de um empregado ser lido quer na forma [cod, count] = fscanf(fid,"%i","C"); [nome, count] = fscanf(fid,"%s","C"); [venc, count] = fscanf(fid,"%f","C"); [data, count] = fscanf(fid,"%s","C"); quer numa só instrução [cod,nome,venc,data,count]=fscanf(fid,"%i%s%f%s","C"); 610Paulo Fernandes Lopes2341.3615/04/1996

9 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 9 Escrita de Ficheiros A escrita de ficheiros depende igualmente do formato utilizado para as strings. Em comprimento fixo, o registo pode ser escrito como fprintf(fid, "%3i", cod); fprintf(fid, "%-25s", nome); fprintf(fid, "%7.2f", venc); fprintf(fid, "%11s", data); fprintf(fid, "%c", \n); ou numa só instrução, como anteriormente. Notar ainda que 1.O sinal – (em %-25s) justifica, à esquerda, o campo nome. 2.Após o último campo deve ser escrito um caracter (\n), para mudança de linha 610 Paulo Fernandes Lopes 2341.36 15/04/1996

10 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 10 Escrita de Ficheiros Em comprimento variável, o registo de um empregado pode ser escrito como fprintf(fid, "%i\t", cod); fprintf(fid, "%s\t", nome); fprintf(fid, "%7.2f\t", venc); fprintf(fid, "%s\n", data); ou numa só instrução, como anteriormente. Notar, que 1.Após cada campo, deve ser escrito o tab (\t) de separação, excepto no último campo, após o que se escreve o caracter (\n) 2.Alguns templates podem ser fixos, (por exemplo, "%7.2f\t) para evitar as convenções por omissão do Octave. 610Paulo Fernandes Lopes2341.3615/04/1996

11 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 11 Selecção de Registos Podemos agora abordar o problema colocado anteriormente: ler um ficheiro de empregados e escrever outro, apenas com os empregados com vencimento superior a 1000 euros. Naturalmente o programa dependerá de os ficheiros serem lidos e escritos em formato fixo ou variável. Assumiremos que esta diferença apenas se reflectirá no campo nome, já que o campo data não contem espaços e pode ser lido em formato cadeia (%s) sem problema.

12 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 12 Selecção de Registos Eis a versão para formato fixo. [f_in, msg_in ] = fopen("empresa_in_fix.txt", "r"); [f_out, msg_out] = fopen("empresa_out_fix.txt", "w"); [cod,nome,venc,data,ct] = fscanf(f_in,"%i%25c%f%s","C"); while !feof(f_in) if venc > 1000 fprintf(f_out,"%3i%-25s%7.2f%11s", cod,nome,venc,data); fprintf(f_out, "%c", "\n"); endif; [cod,nome,venc,data,ct] = fscanf(f_in,"%i%25c%f%s","C"); endwhile; fclose(f_in); fclose(f_out);

13 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 13 Selecção de Registos E eis a versão para formato variável. rem_sp("empresa_in_var.txt", "empresa_aux_var.txt"); [f_aux, msg] = fopen("empresa_aux_var.txt", "r"); [f_out, msg] = fopen("empresa_out_var.txt", "w"); [cod,nome, venc, data, count] = fscanf(f_aux,"%i%s%f%s","C"); while !feof(f_aux) if venc > 1000 fprintf(f_out, "%i\t%s\t%7.2f\t%s\n", cod,nome,venc,data); endif; [cod,nome, venc, data, count] = fscanf(f_aux,"%i%s%f%s","C"); endwhile; fclose(f_aux); fclose(f_out);

14 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 14 Processamento de Registos Podemos agora considerar outro tipo de processamento de registos, que não envolve necessariamente a escrita de novos ficheiros, correspondente a: –Cálculo de totais e médias (de vencimentos, por exemplo) –Determinação de máximos e mínimos (de vencimentos, ou antiguidades) Vamos ilustrar estes problemas com programas para determinação dos vencimentos totais e médios dos empregados da empresa, bem como da determinação do empregado mais antigo. Em ambos os casos apenas apresentamos a versão para formato variável. De notar a instrução printf, que permite escrever no terminal mensagens formatadas (com os formatos usados em ficheiros).

15 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 15 Processamento de Registos O tratamento de vencimentos utiliza um contador (variável i) de registos lidos e uma variável (total) para determinação do total dos vencimentos (sendo a média igual ao quociente total/i). rem_sp("empresa_in_var.txt", "empresa_aux_var.txt"); [f_aux, msg] = fopen("empresa_aux_var.txt", "r"); [cod,nome, venc, data, count] = fscanf(f_aux,"%i%s%f%s","C"); i = 0; total = 0; while !feof(f_aux) i = i+1; total = total +venc; [cod,nome, venc, data, count] = fscanf(f_aux,"%i%s%f%s","C"); endwhile; printf("o total dos vencimentos é de %7.2f \n", total); printf("a média dos vencimentos é de %7.2f \n",total/i); fclose(f_aux); fclose(f_out);

16 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 16 Processamento de Registos O tratamento de datas, implica reconhecer quando uma data é anterior a outra, o que é feito com a função anterior que compara duas datas, sendo armazenada a data menor. rem_sp("empresa_in_var.txt", "empresa_aux_var.txt"); [f_aux, msg] = fopen("empresa_aux_var.txt", "r"); [cod,nome, venc, data, count] = fscanf(f_aux,"%i%s%f%s","C"); data_menor =01/01/2100; while !feof(f_aux) if anterior(data,data_menor) data_menor = data; endif; [cod,nome, venc, data, count] = fscanf(f_aux,"%i%s%f%s","C"); endwhile; printf("a entrada mais antiga foi em %s\n",data_menor); fclose(f_aux); fclose(f_out);

17 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 17 Processamento de Registos A comparação de datas é feita através da comparação dos seus anos, meses e dias, tendo o cuidado de converter as cadeias de caracteres em números. function d = anterior(data1,data2); % data no formato dd/mm/aaaa ano1 = str2num(substr(data1,7,4)); ano2 = str2num(substr(data2,7,4)); if ano1 ano2 d = 0; else mes1 = str2num(substr(data1,4,2)); mes2 = str2num(substr(data2,4,2)); if mes1 mes2 d = 0; else dia1 = str2num(substr(data1,1,2)); dia2 = str2num(substr(data2,1,2)); if dia1 < dia2 d = 1; else d = 0; endif; endfunction

18 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 18 Processamento de Registos Neste último caso, a informação transmitida não é muito interessante. Provavelmente estaremos mais interessados em saber quem é o empregado mais antigo, ou seja, qual o nome do empregado com data de entrada mais antiga. Este problema pode ser resolvido com uma pequena adaptação do código, guardando não só a data mais antiga como o nome while !feof(f_aux) if anterior(data,m_data) data_menor = data; antigo = nome endif; [cod,nome, venc, data, count] =... endwhile; printf("o empregado mais antigo é %s \n", antigo); printf("com data de entrada %s \n", data_menor);

19 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 19 Processamento de Registos Todos estes programas obrigam a ler um ficheiro, cada vez que se pretende responder a uma questão. No entanto, a leitura de ficheiros, mesmo em discos rápidos é tipicamente milhares de vezes mais lenta que a leitura a partir de dados em memória. Haverá pois vantagem em copiar um ficheiro de registos para memória e passar a responder às questões a partir de aí. Veremos como responder a esta questão em geral e, no caso do Octave, como tal poderá ser feitos com estruturas e listas.

20 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 20 Processamento de Informação Alfanumérica Podemos considerar que a informação dos ficheiros de registos corresponde a uma tabela. Esta tabela é constituída por uma sequência de registos, um em cada linha. Se toda a informação fosse numérica, e se cada registo tivesse n campos, ela poderia ser guardada numa matriz com m linhas, uma linha para cada registo de n posições. Em Octave, existe um problema: uma posição de uma matriz não pode ser ocupada por uma cadeia de caracteres!

21 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 21 Processamento de Informação Alfanumérica Desta forma a informação de uma tabela alfanumérica não pode ser guardada como uma matriz. Vamos ver como se podem ultrapassar estes problemas em Octave, fazendo-o em duas fases: –Como representar um registo heterogéneo, com vários campos de diferentes tipos, alguns alfanuméricos. –Como armazenar e aceder a vários destes registos heterogéneos.

22 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 22 Estruturas Vectores e Matrizes são muito úteis quando os dados são todos do mesmo tipo (no Octave, de qualquer tipo numérico). No entanto, em muitos casos, a informação que se pretende agrupar com um só identificador não é do mesmo tipo. Por exemplo, um empregado duma empresa pode ter associado a seguinte informação –Um código (um número?) –Um nome (uma cadeia de caracteres) –Um vencimento (um decimal) –Uma data de entrada (uma cadeia, ou 3 campos numéricos, para o dia, mês e ano)

23 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 23 Estruturas As várias linguagens de programação permitem o agrupamento destes dados heterogéneos, com um mesmo identificador de uma forma variada (records no Pascal, Struct em C,...) O Octave adopta uma designação semelhante à do C, denominando estes agrupamentos como estruturas. Consideremos pois o caso do empregado abaixo, em que gostaríamos de agregar toda a informação numa única variável, do tipo estrutura, que denotaremos como emp_610. emp_610 =

24 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 24 Estruturas As estruturas são compostas por vários campos, cada um com um nome. Na estrutura para representação da informação de empregados, consideraremos os campos abaixo, que guardam a informação esperada –cod: o código do empregado –nome: o nome do empregado –venc: o vencimento do empregado –data: a data de entrada do empregado na empresa. emp_610 =

25 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 25 Estruturas Uma vez definidos os nomes dos campos da estrutura, podemos atribuir-lhe os valores pretendidos. O acesso a um campo da estrutura é feito fazendo suceder ao nome da estrutura o nome do campo pretendido, separado por um ponto (.). Por exemplo, a atribuição dos 4 valores dos campos pode ser feita pelas seguintes atribuições: emp_610.cod = 610; emp_610.nome = Paulo Fernandes Lopes; emp_610.venc = 2341.36; emp_610.data=15/04/1996; emp_610 =

26 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 26 Estruturas De notar que os campos de uma estrutura não são ordenados, e podem ser preenchidos por qualquer ordem. Assim a estrutura que temos referido pode ser inicializada quer com a sequência de instruções empregado.data=15/04/1996; empregado.cod = 610; empregado.nome = Paulo Fernandes Lopes; empregado.venc = 2341.36; ou com outra sequência empregado.venc = 2341.36; empregado.cod = 610; empregado.data=15/04/1996; empregado.nome = Paulo Fernandes Lopes; emp_610 =

27 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 27 Estruturas Uma vez agrupados os vários items de informação numa só variável do tipo estrutura, podemos referir alguns campos depois de verificar outros. Por exemplo, dados vários empregados com o tipo referido, indicar qual o nome dos que ganham mais de 1000 euros. Na sintaxe do Octave, tal poderia ser feito através da instrução condicional if emp_610.venc > 1000 then disp(emp_610.nome) endif No entanto este tipo de processamento só é verdadeiramente útil se tivermos a possibilidade de aceder a todos os empregados de uma forma genérica.

28 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 28 Estruturas Por exemplo, se tivéssemos uma tabela com várias linhas, com códigos na primeira coluna e vencimentos na 2ª coluna, poderíamos apresentar os códigos dos empregados com vencimento superior a 1000 euros através da seguinte instrução iterativa: for i = 1:n if tabela(i,2) > 1000 then disp(tabela(i,1)) endif endfor; Por analogia, o que é necessário é poder aceder a uma sequência de (1 a n) estruturas do tipo da do empregado. Em Octave, essa sequência pode ser implementada através de listas.

29 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 29 Listas Uma lista é uma sequência de dados do mesmo tipo, simples ou complexo, para as quais estão definidas as operações de: Criação: list(elem_1, elem_2,..., elem_k) –Cria uma lista, com os elementos de 1 a k (ou uma lista vazia se k = 0) Acrescento: append(nome_lista,elem_1,...,elem_k) –Acrescenta os os elementos de 1 a k à lista com o nome indicado no 1º argumento Acesso: nth(nome_lista, k) –Acede ao k-ésimo elemento da lista. De notar que esse elemento pode ser uma estrutura arbitrariamente complexa.

30 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 30 Listas Para ilustrar o conceito de lista, vamos considerar um ficheiro com informação sobre empregados e criar uma lista com essa informação. A cada linha do ficheiro corresponde uma estrutura, emp, com os campos cod, nome, venc e data. Por exemplo, A leitura dos vários campos de uma estrutura pode ser feita como anteriormente [emp.cod,emp.nome,emp.venc,emp.data,count] = fscanf(f_aux,"%i%s%f%s","C");

31 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 31 Leitura de Listas O programa completo, que cria uma lista, tab_empregados, com a informação sobre os empregados do ficheiro empresa_aux.txt, é o seguinte: [f_aux, msg] = fopen("empresa_aux.txt", "r"); tab_empregados = list(); n = 0; [emp.cod,emp.nome,emp.venc,emp.data, count] = fscanf(f_aux,"%i%s%f%s","C"); while !feof(f_aux) n = n+1; tab_empregados = append(tab_empregados, emp); [emp.cod,emp.nome,emp.venc,emp.data, count] = fscanf(f_aux,"%i%s%f%s","C"); endwhile; fclose(f_aux);

32 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 32 Estruturas e Listas em Funções Estruturas e listas podem ser retornadas como resultado de uma função. Por exemplo, a função abaixo retorna a lista anterior e o número dos seus elementos: function [tabela, n] = ler_tab_emp(ficheiro); rem_sp(ficheiro, "empresa_aux.txt") [f_aux, msg] = fopen("empresa_aux.txt", "r"); tabela = list(); n = 0; [emp.cod,emp.nome,emp.venc,emp.data, count] = fscanf(f_aux,"%i%s%f%s","C"); while !feof(f_aux) n = n+1; tabela = append(tabela, emp); [emp.cod,emp.nome,emp.venc,emp.data, count] = fscanf(f_aux,"%i%s%f%s","C"); endwhile; fclose(f_aux); endfunction;

33 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 33 Listas A partir deste momento, todo o processamento da informação sobre os empregados pode ser feito sem leitura do ficheiro, mas apenas por acesso à lista tab_empregados. Se já tiver sido lida a informação dos empregados para a lista tab_empregados, com n elementos, ela pode ser acedida directamente, sem necessidade de nova leitura do ficheiro. total = 0; for i = 1:n total = total + nth(tab_empregados,i).venc; endfor; printf("o total de vencimentos é %7.2f \n, total); printf( e a sua média é %7.2f \n", total/n);

34 10 Novembro 2006 Leitura, Escrita e Processamento de Registos - Estruturas e Listas 34 Listas Igualmente se podem escrever o nome e vencimento dos empregados que ganham mais de 1000 euros, sem necessidade de leitura do ficheiro, mas apenas usando a mesma lista tab_empregados, com n elementos. printf("Lista de empregados com mais de 1000 : \n"); for i = 1:n emp = nth(tab_empregados,i); if emp.venc > 1000 printf("\t%s\t%7.2f\t\n",emp.nome,emp.venc); endif; endfor;


Carregar ppt "10 Novembro 2006Leitura, Escrita e Processamento de Registos - Estruturas e Listas 1 Leitura, Escrita e Processamento de Registos Estruturas e Listas Jorge."

Apresentações semelhantes


Anúncios Google