PCS-408 Laboratório de Engenharia de Software e Metodologias de Programação PCS-409 Engenharia de Software I



Documentos relacionados
1 Funções básicas de implementação de arquivos

Conceitos básicos da linguagem C

Introdução. Manipulação de arquivos em C. Estrutura de Dados II Prof Jairo Francisco de Souza

Programação de Computadores I. Linguagem C Arquivos

Gerenciamento de Entrada e Saída Hélio Crestana Guardia e Hermes Senger

Persistência de Dados

Capítulo 6. Gerenciamento de Arquivos. 6.1 Arquivos 6.2 Diretórios 6.3 Implementação (6.3.1 a 6.3.6) 6.4 Exemplos

CADERNOS DE INFORMÁTICA Nº 1. Fundamentos de Informática I - Word Sumário

Trabalho 3: Agenda de Tarefas

5 Apresentando a linguagem C

Linguagem de Programação I

SOP - TADS Sistemas de Arquivos Cap 4 Tanenmbaum

Algoritmos e Programação _ Departamento de Informática

SISTEMAS OPERACIONAIS ABERTOS Prof. Ricardo Rodrigues Barcelar

Sistemas Operacionais. Prof. André Y. Kusumoto

Sistema de Memórias de Computadores

Algoritmos DCC 119. Introdução e Conceitos Básicos

5 - Vetores e Matrizes Linguagem C CAPÍTULO 5 VETORES E MATRIZES

Algoritmos e Estruturas de Dados I 01/2013. Estruturas Condicionais e de Repetição (parte 2) Pedro O.S. Vaz de Melo

Unidade 5: Sistemas de Representação

Capítulo 4 Gerenciamento de Memória

BACHARELADO EM SISTEMAS DE INFORMAÇÃO EaD UAB/UFSCar Sistemas de Informação - prof. Dr. Hélio Crestana Guardia

20 Caracteres - Tipo char

P r o g r a m a ç ã o d e C o m p u t a d o r e s 1 o S e m P r o f. A n d r é A m a r a n t e L u i z L A B 5 tag %2d while printf PE1:

LÓGICA DE PROGRAMAÇÃO. Professor Celso Masotti

Manual do Usuário. Protocolo

GABARITO COMENTADO SISTEMAS OPERACIONAIS. PROF. Cláudio de C. Monteiro, Evanderson S. de Almeida, Vinícius de M. Rios

Introdução à Programação

Mapeamento de memória e programação da IHM do controlador CP-WS41/8DO8DI4AO2AI2TAI

IFPE. Disciplina: Sistemas Operacionais. Prof. Anderson Luiz Moreira

Algoritmos e Programação

Introdução a Programação. Ponteiros e Strings, Alocação Dinâmica

Algoritmos e Programação Estruturada

Sistemas Operacionais Arquivos

Sistema de Arquivos. Ambientes Operacionais. Prof. Simão Sirineo Toscani

Nível da Arquitetura do Conjunto das Instruções

5.1 Sistemas de Arquivos

Arquitetura dos Sistemas Operacionais

Exercícios de Revisão Java Básico

Trabalho 7 Fila de prioridade usando heap para simulação de atendimento

LP II Estrutura de Dados. Introdução e Linguagem C. Prof. José Honorato F. Nunes honorato.nunes@ifbaiano.bonfim.edu.br

Estrutura de Dados Básica

Manual de Operação do Multiconta Drive / Delivery

REPRESENTAÇÃO DE DADOS EM SISTEMAS DE COMPUTAÇÃO AULA 03 Arquitetura de Computadores Gil Eduardo de Andrade

Estruturas de Dados. Profa. Juliana Pinheiro Campos

Capítulo 8. CICLOS. Tabela 8.1 Programa8a.f90.

MODELAGEM E SIMULAÇÃO

Manipulação de Arquivos

9 Comandos condicionais

E/S CPU. Memória (Instruções e dados) 2 PARADIGMA IMPERATIVO. Instruções e dados. Resultados das operações. Unidade lógica e aritmética

Notas de versão. Versão

UNIVERSIDADE FEDERAL DO RIO GRANDE DO SUL INSTITUTO DE INFORMÁTICA INFORMÁTICA APLICADA

Orientação a Objetos

Programação: Estruturas de seleção

OPL9815 Inventário Configurável

Ter o controle das pastas (Prontuários) armazenadas no "SAME", utilizando-se do recurso do "Volume".

Variáveis e Comandos de Atribuição

Armazenamento de Dados. Prof. Antonio Almeida de Barros Junior

1) Ao ser executado o código abaixo, em PHP, qual será o resultado impresso em tela?

INF 1007 Programação II

Montagem e Manutenção. Luís Guilherme A. Pontes

Algoritmos e Estrutura de Dados. Prof. Tiago A. E. Ferreira

1. Fazer um programa em C que pergunta um valor em metros e imprime o correspondente em decímetros, centímetros e milímetros.

MC-102 Algoritmos e Programação de Computadores

Memória cache. Prof. Francisco Adelton

FACENS Engenharia Mecatrônica Sistemas de Computação Professor Machado. Memória Armazenamento Sistema de Arquivos

Algoritmo Iterativo. Dilema do Martelo x Edifício. O Martelo. O Edifício 01/06/2014. Dilema das ações x declarações

DISPOSITIVOS DE BLOCO. Professor: João Paulo de Brito Gonçalves

Definição de Programas de Computadores e Linguagem de Programação de Comutadores

Prof. Rafael Gross.

LINGUAGEM C. Estrutura básica de um programa

INTRODUÇÃO À LINGUAGEM C++

O Sistema foi inteiramente desenvolvido em PHP+Javascript com banco de dados em MySQL.

Implementando uma Classe e Criando Objetos a partir dela

Capítulo 2. VARIÁVEIS DO TIPO INTEIRO

Relatórios. Manual. Pergamum

Estruturas de Dados. Alguns dados não costumam ser tão simples assim... Podem ser compostos por vários dados distintos

Gerência do Sistema de Arquivos. Adão de Melo Neto

Simulado Informática Concurso Correios - IDEAL INFO

Linguagem e Técnicas de Programação I Tipos de dados, variáveis e constantes. Prof. MSc. Hugo Souza Material desenvolvido por: Profa.

Redes de Computadores II

Acessando o SVN. Soluções em Vendas Ninfa 2

Tópicos Avançados em Banco de Dados Gerenciamento de Transações em Banco de Dados. Prof. Hugo Souza

Sistemas Operacionais 3º bimestre. Dierone C.Foltran Jr.

Computadores XXXIII: Posições de memória A8 Texto 3

Sobre o Sistema FiliaWEB

Memória Flash. PdP. Autor: Tiago Lone Nível: Básico Criação: 11/12/2005 Última versão: 18/12/2006. Pesquisa e Desenvolvimento de Produtos

Tabelas vista de estrutura

5. Uma lousa denominada EPI (registrador de endereço de próxima instrução).

Portal do Projeto Tempo de Ser

Computadores Digitais 2. Prof. Rodrigo de Souza Couto

Capítulo SETE Números em Ponto Fixo e Ponto Flutuante

Armazenamento Secundário. SCE-183 Algoritmos e Estruturas de Dados II

Arquitetura de Sistemas Operacionais

Figura 1: tela inicial do BlueControl COMO COLOCAR A SALA DE INFORMÁTICA EM FUNCIONAMENTO?

Transcrição:

1 PCS-408 Laboratório de Engenharia de Software e Metodologias de Programação PCS-409 Engenharia de Software I Prof. Maria Alice Grigas Varella Ferreira 1998 ARMAZENAMENTO DE ARQUIVOS EM DISCOS MAGNÉTICOS 1. Características físicas dos discos magnéticos Uma unidade de disco magnético funciona de forma semelhante aos antigos discos de vitrola, anteriores ao aparecimento dos CDs. O disco gira em torno de um eixo com uma certa velocidade, e um braço se move sobre ele, lendo ou gravando informação. O diagrama esquemático de um disco magnético está apresentado na Figura 1. cabeça de leitura/gravação a) superfícies de gravação r cilindro de raio r r trilha de raio r b) r setor Figura 1 Características físicas de um disco magnético: a) visto de lado; b) visto de cima

2 A unidade de gravação é o byte. Os bits que compõem cada byte - ou caracter - são gravados serialmente sobre a trilha do disco. As trilhas que compõem a superfície do disco são concêntricas e não uma única espiral como é o caso dos discos musicais e a superfície magnética contém um número de trilhas que é função do fabricante escolhido. Pode-se ter várias superfícies por disco. A passagem de uma trilha para outra exige um movimento de erguer o braço, selecionar a trilha e descer novamente o braço. O tempo envolvido é denominado tempo de seek. As trilhas que se dispõem sobre as várias superfícies, a uma mesma distância do centro constituem um cilindro. Uma vez que, no caso de um disco magnético, pode-se movimentar a cabeça de leitura/gravação entre trilhas próximas ou distantes, não é necessário que a leitura/gravação de dados seja feita de forma serial, mas pode ser feita em qualquer ponto do disco. Os dados nesse caso não necessitam ser gravados na mesma ordem em que se encontram dispostos no dispositivo: pode-se gravar o registro de número 1, depois o de número 4, depois o de número 20 e depois de número 2, sem problemas. A esse tipo de operação dá-se o nome de acesso aleatório ou randômico. As operações necessárias para tornar este tipo de acesso possível são transparentes ao programador e são executadas pelo Gerenciador de Entrada e Saída que é parte do Sistema Operacional utilizado. DOS e UNIX são dois Sistemas Operacionais muito utilizados no Brasil. Para que o programador grave/leia registros de forma aleatória ele deve fornecer, além dos dados que compõem o registro, o número de ordem do registro (1, 4, 20 e 2, no parágrafo anterior). As linguagens de programação, geralmente, fornecem comandos que permitem fazer isso de forma bastante simples. Os exemplos apresentados utilizarão a linguagem C. Observa-se que nessa linguagem, entretanto, não existem comandos de entrada e saída, mas utilizam-se chamadas de funções de bibliotecas da linguagem. Nos arquivos randômicos os registros não necessitam estar classificados para que se forme o arquivo. O método de acesso (rotina do Sistema de Entrada e Saída do Sistema Operacional) utiliza o número de ordem do registro para localizá-lo na posição física correspondente, convertendo esse número em: endereço do cilindro, endereço da trilha e posição do registro na trilha. Alguns discos, subdividem a trilha em porções menores, denominadas setores, que também podem fazer parte do endereço físico do registro. A leitura é feita lendo-se o setor todo, o qual pode conter vários registros. Este conjunto é denominado registro físico ou bloco. O bloco é lido em uma área do Sistema Operacional denominada buffer e daí, o registro lógico pedido é transferido para o programa. A figura 2 mostra o processo descrito 2. Características lógicas dos discos Do ponto de vista lógico, um arquivo de acesso aleatório pode ser imaginado como uma matriz de células como a da figura 3. O arquivo do exemplo tem 27 registros, que podem ser lidos ou gravados independentemente um dos outros. Os números colocados dentro das células representam os números de registro ou chaves, e é através delas que se faz a leitura ou gravação do registro.

3 Sistema Operacional buffer programa registro Área livre MEMÓRIA DISCO (ARMAZENAMENTO EXTERNO) Figura 2 Leitura de um registro do disco Suponha-se que se deseje ler, atualizar e gravar novamente os dados do registro marcado na matriz. Para isso, é necessário, antes de mais nada, localizar o registro; os comandos seguintes mostram como fazer isso: deslocamento = (15 1)* sizeof (registro); fseek (meu_arq, deslocamento, SEEK_ SET); Para estes comandos, tem-se que: meu_arq indicador do arquivo em C (ponteiro); deslocamento diferença, em bytes, entre a posição do cursor do arquivo e a nova posição desejada; SEEK_SET posição do cursor considerada; esta constante indica cursor na posição inicial do arquivo. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 Figura 3 - Matriz de células representando um arquivo

4 Na seqüência apresentada, note-se que o deslocamento (calculado em bytes) é dado pelo produto da chave desejada menos 1 (15-1) pelo tamanho de cada registro (dado pela função sizeof ) 3) Arquivos em C Na linguagem C toda Entrada e Saída é feita através de funções de biblioteca. Estas funções são baseadas na estrutura do Sistema Operacional Unix 1. A biblioteca básica é a stdio.h. Os arquivos possuem atributos: tamanho, modos de gravação/leitura (texto ou binário), identificador (o seu nome), etc. Podemos classificar os arquivos em dois grandes grupos: binários e de texto. Os arquivos randômicos são arquivos do tipo binário. Apesar de não ter sido dito no item anterior, ao fazermos a analogia com uma matriz, estamos imaginando que todos os registros da figura 3 têm o mesmo tamanho, já que isso é o que ocorre no caso de uma matriz. A igualdade de tamanho dos registros é que permite escrever a fórmula que dá o deslocamento, utilizado pela função fseek. Cada arquivo em C é uma stream, ou seja, uma "corrente de bytes" (fluxo de bytes). O arquivo possui um cursor que pode ser deslocado sobre esta corrente. Inicialmente ele se encontra no início do arquivo, e à medida que se processa a leitura do arquivo ele se desloca sobre a seqüência de bytes. Esta posição ocupada pelo cursor denomina-se posição corrente (SEEK_CUR, se a contagem é feita a partir desta posição). Assim, para fazermos a leitura de um registro que está numa posição conhecida do arquivo, temos de deslocar o cursor até o início deste registro, ao longo da stream. Esta é a função de fseek. Os arquivos do tipo texto não têm, obrigatoriamente, registros de tamanho fixo. O fim de um registro é marcado por um caracter especial, o end-of-line (eol), que é representado pela tecla Enter. Os arquivos do tipo texto são escritos em código ASCII e contêm brancos, que separam os campos do registro. A leitura destes registros é feita de forma sequencial, ou seja, registro após registro. Arquivos de dados para programas são geralmente deste tipo. As principais operações sobre um arquivo são: atribuição de um descritor (definição do arquivo) 2 abertura/fechamento do arquivo leitura/escrita posicionamento do cursor O modo de gravação dos arquivos influi diretamente sobre as operações que devem ser empregadas na manipulação do arquivo. O Anexo 1 fornece uma lista das funções que executam E/S sobre arquivos em disco, em plataforma DOS, a que foi utilizada para os exemplos. O compilador utilizado foi o Borland C++, versão 3.0. 1 A linguagem C teve sua origem em plataformas Unix. 2 O descritor do arquivo é um apontador (ponteiro) para o arquivo.

5 4. Exemplo: Sistema de Reserva de Passagens Aéreas (muito simplificado) Um sistema de reserva de passagens aéreas tem como finalidade gerar uma Lista de Passageiros para cada vôo de uma dada empresa. Pode-se imaginar que o passageiro, ao chegar ao guichê da companhia, solicita um bilhete para um certo vôo (identificado por um número) entre duas cidades onde a aeronave faz escala. O programa deve incluir o passageiro na Lista de Passageiros correspondente, se a aeronave tiver lugares vagos no trajeto solicitado, ou dar mensagem de erro, em caso contrário. Note-se que os vôos são em geral multiescala. Seja o exemplo da figura 4. SP RIO SALVADOR RECIFE 1 2 3 4 Figura 4 - Vôo 729 São Paulo/Recife No vôo mostrado, a aeronave faz quatro escalas, respectivamente em São Paulo, Rio, Salvador e Recife. Vamos chamar de trajeto cada um dos trechos delimitados por duas escalas. Temos, então, três trajetos: São Paulo - Rio, Rio Salvador e Salvador Recife. O total de passageiros em cada trajeto é variável, porque sempre existem passageiros em trânsito em cada escala. Para aceitar-se um novo passageiro é necessário que haja lugar disponível na aeronave, em cada trajeto, entre as escalas especificadas na requisição do bilhete. O Sistema de Reservas de Passagens Aéreas é de natureza volátil, porque as reservas, feitas aleatoriamente para os diversos vôos, são trocadas ou canceladas, e toda vez que um vôo se efetua, os seus dados se tornam desatualizados (não são mais reservas). Assim sendo, um sistema de arquivos desse tipo tem que ser de acesso direto, a fim de ser atualizado rapidamente e várias vezes ao dia. O sistema será composto por dois arquivos randômicos: 1) Arquivo de Vôos, contendo as informações referentes aos vôos e um ponteiro para a Lista de Passageiros, que está configurada no segundo arquivo. 2) Arquivo de Passageiros, contendo os dados referentes a cada passageiro. Os dados armazenados para cada vôo são: número do vôo; máximo de passageiros por vôo; total de escalas do vôo; passageiros em cada trajeto do vôo; Lista de Passageiros, composta por registros com: RG do passageiro; nome do passageiro; endereço do passageiro; 5

6 CIC do passageiro; escala de origem; escala destino. Efetua-se em seguida uma análise em separado de cada um dos arquivos. 4.1. Arquivo de Vôos O Arquivo de Vôos tem como chave de acesso o número do vôo. Pode-se supor que o número do vôo é composto de 3 dígitos, como no exemplo representado na figura 4 (vôo 729). Assim sendo, pode apresentar valores entre 0 e 999. É verdade, que nem todos os números entre 0 e 999 correspondem a vôos válidos, porém eles terão que constar do arquivo. Este é um preço a ser pago pela facilidade de acesso a um registro desse arquivo. Um exemplo válido de um arquivo desse tipo é mostrado na figura 5, onde os registros apresentados estão entre 0 e 26. 0 1 5 10 11 12 15 22 Figura 5 Arquivo randômico, apresentando registros com vôos válidos As células com números indicam vôos válidos, e as células em branco, vôos inexistentes 3. É comum isso ocorrer em arquivos de acesso direto: somente parte dos registros são utilizados, os demais constituindo uma perda de área de armazenamento. Esta perda é um compromisso entre espaço de armazenamento gasto e flexibilidade de acesso 4. Se o arquivo fosse serial, reservaríamos espaço no disco somente para os vôos existentes, entretanto para incluir um novo vôo (por exemplo, 4) teríamos de regravar todos os registros do arquivo. Observe-se a configuração de um registro do arquivo; considere-se que é da forma apresentada na figura 6. 0 6... Lista de Passageiros Figura 6- Representação gráfica do registro do Arquivo de Vôo 3 Vôo inexistente vôo para o qual a lista de passageiros não se encontra aberta. 4 Flexibilidade de acesso a possibilidade de alterar um registro do arquivo sem ter que regravar o arquivo todo. total de passageiros por trajeto total de escalas no vôo ( 8) máximo de passageiros no vôo 6

7 A escolha desse formato de registro é arbitrária, mas baseou-se em alguns pontos, que são listados a seguir: número do vôo não necessita ser armazenado, pois constitui a própria chave de acesso ao registro; é o valor usado para se calcular o deslocamento, empregado na função fseek. máximo de passageiros no vôo é um número variável, pois depende do avião escalado para aquele vôo. total de escalas no vôo é função do vôo; o vôo do exemplo, (São Paulo - Recife), tem duas escalas intermediárias (Rio e Salvador). Isso implica em passageiros que podem estar escalados para três trajetos diferentes. Um passageiro indo de São Paulo a Recife participa dos três trajetos. total de passageiros por trajeto indica (valor arbitrário) quantos passageiros trafegam em cada trajeto. Sendo o número máximo de escalas oito, o máximo de trajetos é sete, e portanto existem sete posições reservadas para o seu armazenamento. ponteiro, indicado pela seta, endereça a Lista de Passageiros que está armazenada no Arquivo de Passageiros; é um inteiro entre 1 e máximo_passageiros, sendo este valor o total de registros no Arquivo de Passageiros (que é definido quando se inicia o sistema). Para o vôo São Paulo-Recife teríamos o registro mostrado na figura 7. 4 0 1 2 3 4 5 6 iniciado com ponteiro nulo total de passageiros por trajeto (zerados na iniciação) Valores não utilizados iniciados convenientemente na iniciação do vôo máximo_passageiros Figura 7-Registro de Vôo do Vôo 729 - São Paulo-Recife Como se pode ver dos comentários colocados na figura 7, todos os registros do Arquivo de Vôo necessitam de iniciação conveniente. Isto é feito por um programa especial de iniciação de vôo, cujo esquema será visto mais a frente. O total de registros nesse arquivo deve ser definido no instante da iniciação do sistema. 4.2. Arquivo de Passageiros Este arquivo é também de acesso direto e sua chave de acesso é fornecida por 7

8 ponteiros 5. O primeiro desses ponteiros encontra-se no Arquivo de Vôo, no último campo de cada registro. Os demais estão na última posição dos registros de passageiros, como será visto a seguir. O objetivo do Arquivo de Passageiros é guardar dados sobre todos os passageiros de um vôo (Lista de Passageiros). O formato do registro está mostrado na figura 8. RG (8 caracteres) nome (30 caracteres) endereço (30 caracteres) CIC (8 caracteres) origem destino para o próximo registro de passageiros Figura 8 Representação gráfica do registro do Arquivo de Passageiros A escolha desse registro foi feita de forma totalmente arbitrária, porém, em princípio, ele contém informações típicas de uma Lista de Passageiros. Note-se que o registro apresenta em sua última posição o ponteiro que permitirá acesso ao próximo registro de passageiro. A Lista de Passageiros constitui em termos computacionais 6 o que se chama uma lista encadeada, isto é, uma estrutura de dados onde cada célula é encontrada a partir de um endereço colocado na célula anterior. A primeira célula é obtida a partir de um ponteiro de lista (no caso, colocado no Arquivo de Vôos). A última célula contém um ponteiro dito nulo 7 para indicar que não há mais células. Esquematicamente, representa-se como na figura 9. L L Figura 9 - Esquema gráfico de uma lista encadeada. 5 O acesso ao registro do arquivo é feito através de seu índice (posição do registro no arquivo) e que é um valor inteiro. Alguns autores gostam de fazer a distinção entre estes valores inteiros e ponteiros localizados na memória do computador, frequentemente manipulados pelas estruturas de dados na memória. Estes ponteiros representam endereços da memória e não são representados de forma diferente. Assim, costumam-se denominar cursores aos índices de tipo inteiro. 6 da disciplina de Estruturas de Dados 7 NULL ou nil, dependendo da convenção da linguagem. 8

9 4.3. Estrutura de dados lista Uma lista encadeada é uma estrutura dinâmica, isto é, seu conteúdo cresce e decresce com o tempo. Isto é basicamente diferente do que ocorre com as matrizes 8 que têm toda sua área reservada no instante da compilação, ou seja, são estáticas. Sendo dinâmicas, as listas iniciam-se vazias. Por exemplo, no instante de definição de um vôo, a Lista de Passageiros está vazia. Listas vazias têm a representação apresentada na figura 9. À medida que registros (ou células) vão sendo incluídos na lista, ela passa a apresentar a estrutura encadeada da figura. Uma lista é uma estrutura organizada na memória interna do computador. Neste exemplo específico, entretanto, estamos considerando a Lista de Passageiros, definida em armazenamento externo, em um disco, com a finalidade de exemplificar uso de arquivos randômicos. Também, com o uso de Sistemas de Bancos de Dados (SQL, Natural etc) o esquema de arquivos empregado, provavelmente, não seria deste tipo. A situação inicial do Arquivo de Passageiros pode ser imaginada como a usual em um sistema de listas, ou seja: Cada uma das lista, correspondente a cada um dos vôos, se encontra vazia; Existe uma lista, que engloba todos os registros disponíveis, de onde se retiram registros, sempre que se vai incluir um passageiro no vôo. O ponteiro dessa lista pode ser guardado no primeiro registro do arquivo (registro_zero). O Arquivo de Passageiros terá na situação inicial a forma mostrada na figura 10. Esta lista, que liga todos os registros disponíveis no arquivo é chamada de AVAIL LIST ou available, na literatura especializada. 1 2 3 2 3 4 9999 10000 9999 10000 posições não iniciadas Figura 10 Arquivo de Passageiros no instante de iniciação do sistema. O registro de ordem zero (registro_zero) não será utilizado para guardar nenhuma outra informação além do ponteiro usado na retirada de células a serem preenchidas com as informações dos passageiros. Esta situação é comum na manipulação de lista e este registro é normalmente chamado de list head, ou header. O total de registros nesse arquivo é definido no instante de iniciação do sistema (maximo_passageiros). 8 Hoje, com as linguagens mais modernas como C, também as matrizes podem ser estruturadas na forma dinâmica; porém, do ponto de vista conceitual, matrizes são estruturas estáticas. 9

10 4.4. Criação dos Arquivos Arquivos randômicos necessitam ser criados antes de serem utilizados. Portanto, os dois arquivos utilizados pelo programa necessitam passar por este processo de criação. O processo de criação é diferente para cada um dos arquivos: No caso do Arquivo de Passageiros é feita uma só vez. O arquivo é criado com a forma mostrada na figura 10. Nesta figura, toma-se o máximo de passageiros como sendo 10000. No caso do Arquivo de Vôos cria-se o arquivo com todos os registros de vôo zerados. Reinicia-se o registro a cada vez que se abre a Lista de Passageiros de um novo vôo, quando se especifica o total de passageiros na aeronave e o total de escalas. Para isso tem que ser criado, inicialmente, um arquivo totalmente vazio, antes de se iniciar o primeiro vôo. O esquema dos programas de criação pode ser visto na figura 11. Geração do Arquivo de Vôo Geração do Arquivo de Passageiros Arquivo de Vôo Arquivo de Passageiros Iniciação de Vôo Dados A figura 11 apresenta três programas: Figura 11 Diagrama de geração dos arquivos randômicos. Criação do Arquivo de Vôo este programa é executado uma única vez e ele grava no disco todos os registros de vôo (maximo_voo). Criação do Arquivo de Passageiros gera no disco todos os registros de passageiros (máximo_passageiros), conforme o esquema apresentado na figura 10. Iniciação de Vôo grava no Arquivo de Vôo os dados relativos a um vôo, zerando a matriz de trajetos e fazendo nulo o ponteiro da Lista de Passageiros. 10

11 4.5. Formato dos registros dos arquivos A figura 12 apresenta a definição dos registros do Arquivo de Vôo e do Arquivo de Passageiros, respectivamente. A figura mostra também a definição de duas constantes de programa, que definem a máximo de vôos (máximo_vôo) e o máximo de registros de passageiros (máximo_passageiros), dados necessários para a iniciação dos arquivos. A figura 13 apresenta o programa de criação do Arquivo de Vôo e a figura 14 o programa de Criação do Arquivo de Passageiros. #define maximo_passageiros 10000 #define maximo_voos 1000 struct passageiro /* LISTA DE PASSAGEIROS */ { char RG[9]; /* RG do passageiro */ char nome[31]; /* nome do passageiro */ char endereco[31];/* endereco do passageiro */ char CIC[12]; /* CIC do passageiro */ int origem; /* escala de origem */ int destino; /* escala de destino */ int next; /* ponteiro para o proximo passageiro da lista*/ ; struct voo /* DADOS DE UM VOO */ { int totalpassageiros;/* maximo de passageiros na aeronave */ int totalescalas; /* total de escalas no voo, incluido origem e int trajetos[7]; destino */ /* total de passageiros em cada trajeto; nao podem exceder o maximo de passageiros na aeronave*/ int listapassageiros;/* numero do registro, no arquivo de passageiros, onde se encontra o primeiro passageiro deste voo */ ; Figura 12 Formato dos registros, definidos por struct em linguagem C. int cria_arquivo_voo(void) { FILE *stream; /* arquivo de voo */ struct voo registro = {10*0; /* registro auxiliar */ int nvoo; /* numero do voo */ /* abertura do arquivo para escrita */ if ((stream = fopen("voos.dat", "wb")) == NULL){ /* abre arquivo de voos */ fprintf(stderr, "Nao consegue abrir o arquivo de voos.\n"); /* laco de iniciacao dos voos */ for (nvoo=0; nvoo<maximo_voos; nvoo++){ /* busca a partir do inicio do arquivo */ fseek(stream,nvoo*sizeof(registro),seek_set); /* grava dados do registro de voos */ fwrite(&registro, sizeof(registro), 1, stream); /* escreve registro */ fclose(stream); /* close file */ return 0; Figura 13 Criação do Arquivo de Vôo

12 /******************************************************************/ /* Rotina para iniciar arquivo de passageiros. Executa-se uma uni-*/ /* ca vez. O arquivo fica estruturado na forma de uma lista encadeada*/ /* de espaco disponivel. */ /******************************************************************/ int cria_arquivo_passageiro (void) { FILE *stream; /* arquivo de passageiros */ struct passageiro registro; /* registro auxiliar */ int i; /* variavel auxiliar */ /* abertura do arquivo de passageiros para escrita */ if ((stream = fopen("passagei.dat", "wb")) == NULL){ /* open file - binario, para escrita */ fprintf(stderr,"nao consegue abrir o arquivo de passageiros.\n" ); strcpy(registro.nome," "); strcpy(registro.endereco," "); strcpy(registro.cic," "); strcpy(registro.rg, " "); registro.origem=0; registro.destino=0; registro.nome[30]=registro.endereco[30]=registro.cic[11]=registro.rg[8]= 0x00; /* laco de iniciacao do arquivo de passageiros */ for (i=0; i<maximo_passageiros - 1; i++) { registro.next = i+1; /* busca a partir do inicio do arquivo */ fseek(stream, i*sizeof(registro), SEEK_SET); fwrite(&registro, sizeof(registro), 1, stream); /* escreve registro */ registro.next = -1; fseek(stream, i*sizeof(registro), SEEK_SET); fwrite(&registro, sizeof(registro), 1, stream); /* escreve registro */ fclose(stream); /* close file */ return 0; Figura 14 Criação do Arquivo de Passageiros. A observação do código mostrado nas figuras 12, 13 e 14 permite-nos determinar algumas propriedades importantes dos arquivos considerados, que são apresentados na tabela seguinte: Propriedade Arquivo Vôo Passageiro Tamanho do Registro 20 bytes 88 bytes Total de registros 1 000 10 000 Área de Arquivo 20* 1000 = 20 000 bytes 88*10 000 = 880 000 bytes Obs: Cada int é compilado como 2 bytes em C (16-bit) Nas figuras, os comandos destacados indicam a manipulação do disco.

13 4.6. Iniciação de vôo Esta operação deve ser efetuada todas as vezes em que se inicia ou reinicia um vôo. A iniciação será feita a partir de dados que estarão armazenados num arquivo (TEST1.DAT), mas que poderiam ser fornecidos também pelo teclado, se fosse julgado conveniente. A figura 15 apresenta a codificação do programa. Os comandos de manipulação de arquivos se encontram destacados nas listagens. Informação Formato Número do vôo %d (0 a 999) Total de passageiros no vôo %d Total de escalas %d (2 a 8) A figura 15 apresenta a codificação do programa. Os comandos de manipulação de arquivos se encontram destacados nas listagens. /*********************************************************************/ /* Inicia os valores de um novo voo, iniciando os campos correspon- */ /* dentes ao numero de passageiros na aeronave e o total de escalas.*/ /* Os totais de passageiros por escala sao zerados e o ponteiro da */ /* passageiros e' iniciado com o valor vazio (-1, por convencao). */ /*********************************************************************/ int inicia_voo (void) { FILE *stream; /* arquivo de voo */ FILE *dados; /* arquivo de dados de atualizacao dos voos - texto */ struct voo registro = {0,0,0,0,0,0,0,0,0,-1; /* registro auxiliar, parcialmente iniciado com valores adequados */ int nvoo; /* numero do voo */ int nbytes; /* variavel auxiliar - contem o resultado do fread*/ /* abertura do arquivo para escrita */ if ((stream = fopen("voos.dat", "r+b")) == NULL){ /*abre arquivo de voos */ fprintf(stderr, "Nao consegue abrir o arquivo de voos.\n"); /* abertura do arquivo de dados */ if ((dados = fopen("test1.dat", "r")) == NULL){ /* abre arquivo de dados */ fprintf(stderr, "Nao consegue abrir o arquivo de dados.\n"); /* laco de iniciacao dos voos */ nbytes = fscanf(dados,"%d %d %d ", &nvoo,&registro.totalpassageiros, &registro.totalescalas); while (nbytes!= 0 & nbytes!= EOF){ fprintf(stderr,"voo = %d **** capacidade = %d **** total de escalas = %d\n", nvoo,registro.totalpassageiros,registro.totalescalas); if (consiste_dados_voo(nvoo,registro.totalpassageiros, registro.totalescalas) == 0) { /* busca a partir do inicio do arquivo */ fseek(stream, nvoo*sizeof(registro), SEEK_SET); /* grava dados do registro de voos */ fwrite(&registro, sizeof(registro),1,stream);/*escreve registro */ /* le dados de um novo voo */ nbytes = fscanf(dados, "%d %d %d",&nvoo,&registro.totalpassageiros,

14 &registro.totalescalas); fclose(stream); /* close file */ return 0; Figura 15 Programa de Iniciação de Vôo A figura 16 mostra o relatório contendo as mensagens de saída, impressas pelo programa. Vôo = 34 **** capacidade = 120 passageiros **** total de escalas = 4 Vôo = 78 **** capacidade = 130 passageiros **** total de escalas = 3 Vôo = 23 **** capacidade = 45 passageiros **** total de escalas = 5 Vôo = 7 **** capacidade = 34 passageiros **** total de escalas = 9 Total de Escalas Invalido (9) Vôo = 90 **** capacidade = 132 passageiros **** total de escalas = 4 Figura 16 Relatório da iniciação de vôo. Note-se as mensagens de erros. Da figura 16 percebe-se que todos os dados fornecidos ao programa são impressos. A consistência sobre esses dados é feita quanto à validade do número do vôo e à validade do número de escalas no vôo. Não dá para verificar a validade do número de passageiros permitidos num vôo porque este depende da aeronave considerada. A listagem da figura 16, permite a conferência visual dos dados. A figura 17 apresenta o programa que faz esta consistência. /************************************************************************/ /* rotina para fazer a consistencia dos dados referentes a um voo */ /* - retorna 1 se: numero do voo invalido (menor que zero ou maior que */ /* maximo_voos - 1) */ /* numero de escalas invalido (menor que 2 ou maior */ /* oito) */ /* numero de passageiros invalido (menor que 1) */ /* - retorna 0 se todos os valores fornecidos sao validos */ /************************************************************************/ int consiste_dados_voo(int nvoo, int numeropassageiros, int numeroescalas) { if (nvoo > maximo_voos - 1 nvoo < 0){ fprintf(stderr, "Numero do voo invalido = %d \n",nvoo); if (numeropassageiros < 0){ fprintf(stderr, "Numero de passageiros invalido (%d) no voo %d \n", numeropassageiros, nvoo); if (numeroescalas > 8 numeroescalas < 2){ fprintf(stderr, "Numero de escalas invalido (%d) no voo %d \n", numeroescalas,nvoo); return 0; Figura 17 Consistência das informações de um vôo

15 4.7. Inclusão de passageiro na lista de um vôo O esquema dessa operação está mostrado na figura 18 Arquivo de Vôo Arquivo de Passageiros relatório Inclusão de passageiro Dados do passageiro Figura 18 Diagrama de Inclusão de Passageiros. A inclusão de um passageiro na lista de vôo se resume nos seguintes passos: ler dados do passageiro e da rota; verificar se a rota é válida; se não for, dar mensagem de erro e ignorar o passageiro; sendo válida a rota, verificar se há vaga para o passageiro nos trajetos da rota; deve-se verificar se há vaga em cada trajeto da rota; se não houver, dar mensagem de erro, e ignorar o passageiro; se o passageiro for aceito, incrementar o total de passageiros em cada trecho e incluir o passageiro no Arquivo de Passageiros; repetir os passos anteriores até se esgotarem os dados. Consideremos que todas as informações são fornecidas através de um Arquivo de dados em formato texto, como foi feito para a Iniciação de Vôos. Neste caso, o mais lógico seria alimentar os dados via terminal, porém a opção de arquivo é mais simples, num exemplo didático. O formato dos dados é mostrado a seguir. Como o sistema lida com dados do tipo caracter, a formatação dos dados é necessária para efetuar a leitura corretamente, donde a obrigatoriedade de colocação dos dados em determinadas colunas do arquivo. A figura 19 apresenta o programa. Informação Formato Número do vôo %d (0 a 999) Escala de início do vôo %d (1 a total de escalas 1) Escala final do vôo %d (2 a total de escalas RG do passageiro 8 caracteres (início na coluna 79) CIC ( 9 dígitos + 2 de controle) 11 caracteres (início na coluna 68) Nome do passageiro 30 caracteres (início na coluna 8) Endereço do passageiro 30 caracteres (início na coluna 38)

16 /************************************************************************/ /* rotina para fazer a consistencia dos dados referentes a uma */ /* inclusao de passageiro */ /* - retorna 1 se: escala inicial invalida (menor que 1 ou maior que o */ /* (total de escalas do voo - 1) */ /* escala final invalida (menor que 2 ou maior que o */ /* total de escalas do voo */ /* - retorna 0 se os valores fornecidos sao validos */ /************************************************************************/ int consiste_dados_inclusao(int escalainicial, int escalafinal, int totalescalas) { if (escalainicial < 1 escalainicial > totalescalas-1){ fprintf(stderr, "Escala inicial invalida (%d)\n", escalainicial); if (escalafinal < 2 escalafinal > totalescalas){ fprintf(stderr, "Escala final invalida (%d)\n", escalafinal); return 0; FILE *stream; /* arquivo de passageiros */ FILE *stream_voo; /* arquivo de voo */ FILE *dados; /*arquivo de dados de atualizacao dos passageiros - texto */ FILE *relatorio; /* arquivo de relatorio */ struct passageiro registro, /* registro auxiliar, para passageiros */ primeiro_registro; /* primeiro registro de passageiros */ struct voo registro_voo; /* registro auxiliar, para voos */ int nvoo; /* numero do voo */ char buf[90]; int ha_vaga; /* variavel para teste de vaga na aeronave */ int i; int indice; /* registro onde serao gravados os dados do passageiro */ int codigo_retorno; /* codigo de retorno dos arquivos */ int nbytes; /* variavel auxiliar - contem o resultado do fread*/ /*******************************************************************/ /* rotina para ler dados do passageiro, e aquisicao de um registro*/ /* do arquivo para incluir seus dados. Facilita a escrita do */ /* trecho e mantem a compatibilidade das varias leituras */ /*******************************************************************/ int ler_dados(void) { /* inclusao de passageiros - ha' espaco nas listas? */ fseek(stream,0,seek_set); /* ler primeiro registro */ fread(&primeiro_registro,sizeof(primeiro_registro),1,stream); if (primeiro_registro.next == -1){ /* verifica se ha posicoes para inclusao de passageiros */ fprintf(stderr, "Nao ha' espaco para incluir passageiros.\n"); ; /* ler registro para incluir passageiro e dados para inclusao */ indice = primeiro_registro.next; fseek(stream,indice*sizeof(registro),seek_set); /* ler registro para incluir passageiro */ fread(&registro,sizeof(registro),1,stream); /* le registro de passageiro*/ primeiro_registro.next = registro.next; nbytes = fread(buf,88,1,dados);

17 strncpy(&registro.nome,&buf[8],30); strncpy(&registro.endereco,&buf[38],30); sscanf(buf,"%d strncpy(&registro.cic,&buf[68],11); %d %d", &nvoo,&registro.origem,&registro.destino); strncpy(&registro.rg,&buf[79],8); /***********************************************************************/ /* rotina para incluir passageiros. Os dados são lidos de um arquivo de*/ /* texto, TEST2.DAT. */ /***********************************************************************/ int inclui_passageiro(void) { /* abertura do arquivo para escrita */ if ((stream_voo=fopen("voos.dat","r+b")) == NULL){/*abre arquivo de voos */ fprintf(stderr, "Nao consegue abrir o arquivo de voos.\n"); /* abertura do arquivo para leitura de passageiros*/ if ((stream = fopen("passagei.dat", "r+b")) == NULL){ /* abre arquivo de passageiros, binario, para leitura e atualizacao */ fprintf(stderr, "Nao consegue abrir o arquivo de passageiros.\n"); /* abertura do arquivo de relatorio */ if ((relatorio = fopen("relatori.dat", "wt")) == NULL){ /* abre arquivo de relatorio, tipo texto, para impressao */ fprintf(stderr, "Nao consegue abrir o arquivo de relatorio.\n"); /* abertura do arquivo de dados */ if ((dados = fopen("test2.dat", "r")) == NULL){ /* abre arquivo de dados */ fprintf(stderr, "Nao consegue abrir o arquivo de dados.\n"); /* iniciacao */ registro.nome[30]=registro.endereco[30]=registro.rg[8]=registro.cic[11]= 0x00; ler_dados(); while (nbytes!= 0 & nbytes!= EOF){ fprintf(relatorio,"%d %d %d\n%s\n%s\n%s\n%s\n", nvoo,registro.origem, registro.destino,registro.nome,registro.endereco, registro.cic,registro.rg); /* imprime dados do relatorio */ if (nvoo > maximo_voos - 1 nvoo < 0){ fprintf(relatorio, "Numero do voo invalido = %d \n",nvoo); else { /* busca a partir do inicio do arquivo */ fseek(stream_voo,nvoo*sizeof(registro_voo),seek_set); fread(&registro_voo,sizeof(registro_voo),1,stream_voo); if (consiste_dados_inclusao(registro.origem, registro.destino,registro_voo.totalescalas) == 0) { /* verifica se ha' vaga em todos os trajetos */ ha_vaga=0; for(i=registro.origem-1; i<registro.destino-1;i++) if(registro_voo.trajetos[i] == registro_voo.totalpassageiros) ha_vaga++; if (ha_vaga == 0) { /* incrementa o total dos trajetos do voo considerado*/ for (i=registro.origem-1; i<registro.destino-1;i++) registro_voo.trajetos[i]++; registro.next = registro_voo.listapassageiros; registro_voo.listapassageiros = indice; /* gravar registro de voo */ fseek(stream_voo,nvoo*sizeof(registro_voo),seek_set); fwrite(&registro_voo,sizeof(registro_voo),1,stream_voo); /* gravar registro de passageiro */ fseek(stream,indice*sizeof(registro),seek_set);

18 /* gravar primeiro registro de passageiros */ fseek(stream,0,seek_set); fwrite(&registro,sizeof(registro),1,stream); fwrite(&primeiro_registro,sizeof(registro),1,stream); fprintf(relatorio,"**** Incluido\n"); else { fprintf(relatorio,"nao ha' vaga no trajeto solicitado\n"); ler_dados(); fclose(stream); /* close file */ fclose(stream_voo); fclose(relatorio); return 0; Figura 19 Programa de inclusão de passageiro A figura 20 mostra a saída impressa desse programa, para dois passageiros. 3 1 2 Maria Lucia Silveira Rua Pedro de Toledo,999 Santos 22233344455 3286667 **** Incluido 3 1 2 Luis Paulo Tibirica R. Siqueira, 556 Andradina 77788899900 3334445 Nao ha' vaga no trajeto solicitado Figura 20 Relatório sobre os passageiros incluídos nas Listas de Passageiro.