27
5 de Maio de 200 5 Registos em Ficheiros 1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

Embed Size (px)

Citation preview

Page 1: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 1

Registos em Ficheiros - Estruturas

Pedro BarahonaDI/FCT/UNL

Maio 2005

Page 2: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 2

Registos em Ficheiros• Muita informação alfanumérica está registada em ficheiros, na

forma de “registos”. Por exemplo, numa base de dados da 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 €.

cod nome vencimento data

610 Paul o Fer nandes Lopes 2341. 36 15/ 04/ 1996825 Pedr o Vi ei r a 989. 24 25/ 06/ 1999316 Mar t a Cost a Mar t i ns 1389. 17 05/ 01/ 199234 Rui Vasco Per ei r a 5310. 32 15/ 04/ 1996723 J or ge Bar at a 767. 26 03/ 09/ 2002

Page 3: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 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).

cod nome vencimento data

610 Paul o Fer nandes Lopes 2341. 36 15/ 04/ 1996825 Pedr o Vi ei r a 989. 24 25/ 06/ 1999316 Mar t a Cost a Mar t i ns 1389. 17 05/ 01/ 199234 Rui Vasco Per ei r a 5310. 32 15/ 04/ 1996723 J or ge Bar at a 767. 26 03/ 09/ 2002

Page 4: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 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’).

cod nome vencimento data

610 Paul o Fer nandes Lopes 2341. 36 15/ 04/ 1996825 Pedr o Vi ei r a 989. 24 25/ 06/ 1999316 Mar t a Cost a Mar t i ns 1389. 17 05/ 01/ 199234 Rui Vasco Per ei r a 5310. 32 15/ 04/ 1996723 J or ge Bar at a 767. 26 03/ 09/ 2002

Page 5: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 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 .

Page 6: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 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;

Page 7: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 7

Leitura de FicheirosComprimento 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");

610 Paulo Fernandes Lopes 2341.36 15/04/1996

Page 8: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 8

Leitura de FicheirosComprimento 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");

610 Paulo Fernandes Lopes 2341.36 15/04/1996

Page 9: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 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, "%10s", data);

fprintf(fid, "%c", “\n”);

ou numa só instrução, como anteriormente. Notar ainda que1. 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 linha610Paulo Fernandes Lopes 2341.3615/04/1996

Page 10: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 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.

610 Paulo Fernandes Lopes 2341.36 15/04/1996

Page 11: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 11

Selecção de Registos

• Podemos agora abordar o problema inicialmente colocado: 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.

Page 12: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 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%c", 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);

Page 13: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 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);

Page 14: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 14

Processamento de Registos

• Podemos agora considerar outro tipo de processamento de informação, 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).

Page 15: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 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);

Page 16: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 16

Processamento de Registos• O tratamento de datas, implica reconhecer quando uma data é

anterior a outra, o que é feito com a função “data_comp” 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 data_comp(data,data_menor) = -1 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);

Page 17: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 17

Processamento de Registos

• A comparação de datas é feita através da comparação dos seus anos, meses e dias, tendo primeiro o cuidado de converter as cadeias de caracteres em números.

function d = data_comp(data1,data2);% data no formato dd/mm/aaaa

ano1 = str2num(substr(data1,7,4));

ano2 = str2num(substr(data2,7,4));

mes1 = str2num(substr(data1,4,2));

mes2 = str2num(substr(data2,4,2));

dia1 = str2num(substr(data1,1,2));

dia2 = str2num(substr(data2,1,2));

d = d_comp(ano1, mes1, dia1, ano2, mes2, dia2);

endfunction

Page 18: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 18

Processamento de Registos

Uma vez obtidos os anos, dias e meses as datas podem ser comparadas, comparando-se sucessivamente os anos, e se necessário os meses e dias.

function d = d_comp(ano1, mes1, dia1, ano2, mes2, dia2);

if ano1 < ano2 d = -1;

elseif ano1 > ano2 d = 1;

elseif mes1 < mes2 d = -1;

elseif mes1 > mes2 d = 1;

elseif dia1 < dia2 d = -1;

elseif dia1 > dia2 d = 1;

else d = 0;

endif

endfunction

Page 19: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 19

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 nomewhile !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);

Page 20: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 20

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.

Page 21: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 21

Estruturas• Embora Vectores e Matrizes sejam muito úteis quando os

dados são todos do mesmo tipo (no Octave, de qualquer tipo numérico), 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)cod nome venc data610 Paulo Fernandes Lopes 2341.36 15/04/1996

Page 22: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 22

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.

cod nome venc data610 Paulo Fernandes Lopes 2341.36 15/04/1996emp_610 =

Page 23: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 23

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 abixo, 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.

cod nome venc data610 Paulo Fernandes Lopes 2341.36 15/04/1996emp_610 =

Page 24: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 24

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 estarutura 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”;

cod nome venc data610 Paulo Fernandes Lopes 2341.36 15/04/1996emp_610 =

Page 25: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 25

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 sequeência empregado.venc = 2341.36;

empregado.cod = 610;empregado.data=“15/04/1996”;empregado.nome = “Paulo Fernandes Lopes”;

cod nome venc data610 Paulo Fernandes Lopes 2341.36 15/04/1996emp_610 =

Page 26: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 26

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.

Page 27: 5 de Maio de 2005Registos em Ficheiros1 Registos em Ficheiros - Estruturas Pedro Barahona DI/FCT/UNL Maio 2005

5 de Maio de 2005 Registos em Ficheiros 27

Estruturas• Por exemplo, se tivessemos 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.

1 2

1 610 2341. 362 825 989. 243 316 1389. 174 34 5310. 325 723 767. 26... . . . . . .