• Nenhum resultado encontrado

AulaLab12

N/A
N/A
Protected

Academic year: 2021

Share "AulaLab12"

Copied!
6
0
0

Texto

(1)

1 Uma memória excelente não faz um

filósofo, assim como um dicionário não pode ser chamado de gramática. John Henry, Cardinal Newman.

ARQUIVOS

A motivação para utilizar arquivos é que o

armazenamento de dados em variáveis, vetores e estruturas declaradas em um programa é temporário. A conservação permanente de grandes quantidades de dados deve ser realizada em dispositivos secundários tais como discos magnéticos, discos óticos e fitas. Para tanto, é necessário empregar o conceito de arquivo:

• Arquivo físico: seqüência de bytes armazenados em disco. Um disco pode conter centenas de milhares de arquivos físicos distintos.

• Arquivo lógico, stream ou descritor: é o arquivo segundo o ponto de vista do aplicativo que o acessa.

Uma stream é o fluxo de dados de um programa para um dispositivo como um arquivo físico ou outros dispositivos de E/S: monitor de vídeo e teclado. Neste processo, existe uma área da memória que é usada temporariamente para armazenar os dados, antes de enviar os mesmos para o seu destino, chamada de buffer.

Com a ajuda do buffer, o sistema operacional pode aumentar a sua eficiência, reduzindo o número de acessos aos dispositivos E/S. Por padrão, todas as

streams utilizam o buffer.

OPERAÇÕES COM ARQUIVOS

Para abrir um arquivo qualquer, a primeira

operação a ser realizada é ligar uma variável de um programa (stream) a um arquivo (físico). Isto pode ser realizado através da criação de uma variável do tipo ponteiro para o tipo FILE (definido no arquivo <stdio.h>) que será associada a um arquivo através do comando fopen de acordo com a seguinte sintaxe:

FILE *arq;

arq = fopen(“nome_arq”, “modo” ); onde: “nome_arq” é o nome do arquivo que se quer abrir (por exemplo, “arquivo.dat” ou “Z:\\LP\\arquivo.dat”) de acordo com “modo”. Existem os seguintes modos de abertura, descritos na

Tabela T1:

Modo Descrição

“r” Leitura, caso não possa abrir devolve NULL.

“w” Escrita, cria ou sobrescreve um arquivo já existente. Caso não possa criar devolve NULL.

“a” Acrescenta, coloca no final do arquivo os novos dados. Caso o arquivo já exista, funciona como “w”.

“r+” Abertura para leitura e escrita. “rt” Leitura de arquivo texto. “rb” Leitura de arquivo binário.

Tabela T1: Modos de leitura.

O comando para se fechar um arquivo é

fclose. Ao se fechar um arquivo a ligação

entre a variável e o arquivo existente no

disco é encerrada e todos os dados que possam existir em buffers associados ao arquivo são gravados fisicamente em disco (flushed). A memória alocada pela função

fopen para a estrutura do tipo FILE é

liberada. A sintaxe da função fclose é:

fclose(FILE *arq);

PT1: Construa um programa que indique

se um determinado arquivo pode ou não ser aberto. #include <stdio.h> main() { FILE *fp; char s[100];

puts(“Introduza o Nome do Arquivo:”); gets(s);

// Abrir arquivo. fp = fopen(s, “r”);

// Verificar se foi ou não realizada a // abertura do arquivo.

if (fp == NULL)

printf(“Impossível abrir o arquivo %s\n”,s);

else

printf(“Arquivo %s aberto com sucesso!!! \n”,s);

fclose(fp);

}

Observe que no programa anterior se a abertura falhar, então, será colocado o valor NULL no ponteiro para o arquivo. Se o arquivo puder ser aberto, é colocado em fp o endereço da estrutura criada por

(2)

2 PT2: Reescreva o PT1 de forma que a

operação de abertura de um arquivo seja realiza por uma função e o usuário possa inserir o nome do arquivo pelo teclado.

#include <stdio.h> #include <conio.h> #include <stdlib.h> #define MODO "w"

// Apelido para vetor tipo char: cadeia. typedef char *cadeia;

// Protótipo de função.

FILE *AbreArquivo(cadeia path, cadeia modo);

main() {

FILE *fp;

cadeia ARQ;

printf("Digite o nome do arquivo: ");

gets(ARQ);

printf("O arquivo e: %s",ARQ); fp = AbreArquivo(ARQ,MODO); fclose(fp);

system("PAUSE"); }

FILE *AbreArquivo(cadeia path, cadeia

modo) {

FILE *arq;

arq = fopen(path, modo);

if (arq == NULL)

{ printf("\n O arquivo %s nao foi criado.",path); getch(); exit(1); } else {

printf("\n Arquivo %s criado com sucesso.",path);

}

return arq; }

LEITURA E ESCRITA

Para ler e escrever em arquivos tipo texto,

ou seja, arquivos onde a informação pode ser visualizada e modificada utilizando-se um editor de textos (por exemplo, o bloco de notas), devem ser usados os comandos de entrada e saída formatada fscanf e

fprintf. Esses comandos funcionam da

mesma forma scanf e printf, tendo apenas mais um parâmetro inicial que indica em qual arquivo o processamento será realizado. Sua sintaxe é dada por: fscanf(FILE *arq, “format”, “args”); onde: format é a tag relativa ao tipo da variável (%d, %f, %c, %s) e args são as variáveis cujo conteúdo será manipulado pelos comandos.

PT3: Escreva um arquivo “dados.txt” no Aplicativo “Notepad” ou “Bloco de notas” uma matriz tal como abaixo:

#include <stdio.h> #include <stdlib.h> main() { int a[3][3], i, j; FILE *arq;

// Verificando se existe o arquivo ! if ( (arq=fopen("dados.txt", "r")) == NULL)

{

printf("Erro ao abrir dados.txt \n"); exit(0); // termina o programa.

}

// Leitura dos dados. for (i=0; i < 3; i++) for (j=0; j < 3; j++)

fscanf(arq, "%d", &a[i][j]);

fclose(arq); // Após ler, fechar arquivo. }

PE1: Modifique o PT3 para que os

valores lidos e armazenados na matriz a sejam mostrados na tela.

PT4: Modifique o PT3 para que o mesmo

seja capaz de realizar alocação dinâmica de memória e possa ler os dados do seguinte arquivo “dados2.dat” dado por:

Observe que os dois primeiros valores correspondem ao número de linhas e colunas da matriz.

(3)

3 #include <stdio.h> #include <stdlib.h> #include <conio.h> main() { int **a; int m,n, i, j; FILE *arq;

// Verificando se o arquivo existe ! if ( (arq = fopen("dados2.txt", "r")) == NULL)

{

printf("Erro ao abrir dados2.txt \n"); getch();

exit(0); // termina o programa. }

// Leitura dos dados do arquivo. fscanf(arq,"%d %d",&m,&n); // Alocação dinâmica.

a = (int **) calloc(m, sizeof(int *)); for (i = 0; i < m; i++)

a[i] = (int *) calloc(n,sizeof(int)); for (i = 0; i < m; i++) for (j = 0; j <n; j++) fscanf(arq,"%d",&a[i][j]); // Fechando o arquivo. fclose(arq); // Impressao na tela. printf("A = \n"); for (i=0; i < m; i++) { for (j=0; j < n; j++) printf(" [%4d] ", a[i][j]); printf("\n"); } system("pause"); }

PE2: Modifique o PT4 para ser capaz de

ler uma matriz A e um vetor b fornecidos no arquivo dados3.dat.

A partir dos valores da matriz A e do vetor b, calcule e mostre o valor de um vetor x que é obtido por x = A*b.

PE3: Modifique o PT4 para a impressão

da matriz A não seja na tela e sim em outro arquivo “dataout.txt”.

PE4: Combine o PE2 e o PE3 e imprima

o valor do vetor x obtido no PE2 usando o arquivo descrito no PE3.

PT5: Criar um programa no qual uma lista

de nomes é fornecida pelo usuário através do teclado. Após a leitura, cada nome é gravado em um arquivo lista.txt:

#include <stdio.h>

main() {

char amigo[80]; char n_arq[80];

FILE *arq;

printf(“Entre nome do arquivo:”); gets(n_arq);

if ( (arq = fopen(n_arq, “w”)) == NULL)

{

exit(1); // termina execução do progr }

// Laço que lê e armazena os nomes. do { printf(“Amigo:”); gets(amigo); fprintf(arq, “%s \n”, amigo); } while ( *amigo != ‘\0’);

fclose(arq); // Fecha arquivo ! }

Observe que o programa PT5 lerá os nomes e os escreverá no arquivo lista.txt até que <ENTER> seja pressionado.

PE5: Modifique o PT5 para imprimir na tela

cada nome gravado no arquivo.

PE6: Modifique o PT5 para que a condição

de parada de leitura de strings use a condição: amigo[0] != ‘\0’.

Um outro comando útil é aquele que verifica se o final de um arquivo foi atingido. O final de um arquivo é indicado através do caractere EOF. O comando para identificar se o final de um arquivo atingido é feof e sua sintaxe é:

feof(FILE *arq);

PT6: Criar um programa que lê cada letra

contida em um arquivo e imprime em outro arquivo todas as letras em maiúsculas (use o comando toupper da biblioteca <ctype.h>) até encontrar o final do arquivo.

(4)

4 #include <stdio.h>

#include <ctype.h> main()

{

FILE *in, *out;

char c;

in = fopen(“entrada.txt”, “r”); out = fopen(“saida.txt”, “w”); if ( in == NULL)

{

printf(“Erro ao criar %s”, in); exit(1); // termina o programa. }

while ( !feof(in) ) // ate o fim arquivo. {

c = fgetc(in); // lê caractere de in. printf(“%c”,c); fputc(toupper(c),out); // escreve em out } fclose(in); fclose(out); }

Observe que no programa anterior foram utilizados os commandos fgetc e fputc para leitura e escrita de caracteres em arquivos. A sintaxe e funcionamento destes comandos é semelhante a dos comandos getc e putc usados para impressão de caracteres na tela.

ARQUIVOS BINÁRIOS

Nos exemplos anteriores foram processados arquivos tipo texto. Nestes arquivos existe um formato interno que separa os caracteres existentes no arquivo por linhas através do comando ‘\n’. Os arquivos binários correspondem a

arquivos de dados, executáveis, jogos, etc. Nos arquivos binários não faz sentido ler uma linha, pois os mesmos estão organizados de forma diferente. Basicamente, para ler os dados destes arquivos é necessário utilizar operações denominadas de acesso direto, onde os dados são escritos em blocos de memória para o disco e lidos em blocos do disco para a memória. Assim, é possível escrever um vetor inteiro em disco de uma só vez, enquanto usando arquivo texto seria necessário escrever elemento por elemento. O mesmo é válido ao se carregar dados a partir de um arquivo binário, sendo, portanto, mais rápido a manipulação de dados em arquivos binários. Outra vantagem é que a informação codificada no arquivo binário ocupa menos espaço, bem como fica automaticamente encriptada, pois apenas o programador sabe como os dados foram escritos e podem ser lidos (uma vantagem para armazenar dados confidenciais como listas de e-mail, cadastro de clientes e dados de movimentação financeira). As funções de leitura e escrita que permitem

acesso direto são fread e fwrite: int fread(&var, numbytes, cont, FILE *ptr);

onde: &var é o endereço para onde a nformação será lida, numbytes é o tamanho do bloco de memória a ser lida (em bytes), cont é o número de blocos a serem lidos, ptr é um ponteiro associado ao arquivo de leitura e int é o número de itens que conseguiu ler com sucesso

(Atenção, o número de itens é (0...n) e não o número de bytes lidos).

int fwrite(&var, numbytes, cont, FILE *ptr);

onde: &var é o endereço da onde a informação será lida e int é o número de itens que foram escritos com sucesso (ou seja, retorna (0...n) e não o número de bytes escritos).

PT7: Escrever um programa que leia do

teclado um vetor com 10 inteiros e guarde seus valores no arquivo DADOS.TXT.

#include <stdio.h> #include <stdlib.h> main() { FILE *fp; int i, v[10];

// Lendo dados do teclado. for (i=0; i<10; i++)

{

printf(“Elemento %d do vetor”,i+1); scanf(“%d”,&v[i]);

}

// Abrir o arquivo DADOS.BIN if ( (fp = fopen(“DADOS.BIN”, “w”)) == NULL)

{

printf(“Nao foi possivel criar arquivo”); exit(1);

}

if (fwrite(v, sizeof(int), 10, fp) != 10)

printf(“Nao foram escritos todos os elementos”);

fclose(fp); }

(5)

5

Verifique usando um editor de texto a formatação do conteúdo do arquivo DADOS.TXT gerado pelo PT7. Além disso, observe que no PT7 a função fwrite escreve de uma só vez os 10 elementos do vetor v, cada um ocupando o espaço de memória igual à sizeof(int). Outra observação importante é que v equivale à &v[0], e, portanto, ao se usar v no comando

fwrite, na verdade é fornecido o endereço

de memória do primeiro elemento do vetor v que se quer escrever e os demais elementos são obtidos a partir deste endereço (lembre-se que no comando fwrite é passado o número de elementos que serão lidos). Uma alternativa de utilização da mesma instrução, que ilustra este mecanismo, é escrever um elemento do vetor por vez através da aritmética de ponteiros:

for (i=0; i < 10; i++)

fwrite(v+i, sizeof(int), 1, fp);

Para se escrever uma variável x do tipo

double, então, o comando seria dado por: fwrite(&x, sizeof(double), 1, fp); ou

fwrite(&x, sizeof(x), 1, fp);

Note que neste caso será usado o operador de endereço &.

PT8: Escrever um programa que carregue

10 vetores inteiros lidos do arquivo DADOS.TXT (construído com o PT7). Depois mostrar os valores da tela.

#include <stdio.h> #include <stdlib.h> main() { FILE *fp; int i, v[10], n;

// Abrir o arquivo DADOS.BIN if ( (fp = fopen(“DADOS.BIN”, “r”)) == NULL)

{

printf(“Nao foi possivel abrir arquivo”); exit(1); } // Lê os dados e coloca em v. n = fread(v, sizeof(int), 10, fp); fclose(fp); // Mensagem de erro. if (n != 10)

printf(“Foram lidos apenas %d elementos !!! \n”, n);

// Apresentando os dados ao usuário. for (i=0; i < n; i++)

{

printf(“v[%d] = %d \n”, i, v[i]); }

}

PE7: Refazer o PE2 utilizando arquivos

binários.

ACESSO A UM ARQUIVO

O acesso da informação contida em um

arquivo pode ser realizado de duas formas:

• Acesso Seqüencial: O arquivo deve ser percorrido na seqüência em que estão escritas as informações até ser encontrada a informação desejada.

• Acesso Direto: Ir diretamente à posição em que se encontra a informação desejada, sem ter que percorrer todos os bytes que estão nesta posição.

Sempre que se abre um arquivo através da função fopen, é criada na memória uma estrutura do tipo FILE que contém a informação sobre o arquivo que se está processando. Dentre as informações contidas na estrutura FILE existe uma que indica a posição em que a leitura ou a escrita está dentro do arquivo (ponteiro de acesso). Sempre que se abre um arquivo para leitura (“r”) ou escrita (“w”), o ponteiro de acesso tem como posição inicial aquela antes do primeiro byte. Se o arquivo for aberto com a opção acrescentar (“a”), então, a posição inicial do ponteiro de acesso será aquela após o último byte do arquivo. A noção de posicionamento dentro de um arquivo só é válida para arquivos binários. Dentre os comandos existentes para navegar dentro de um arquivo binário existem os descritos na

Tabela T2:

Comando Descrição

rewind(fp); Volta a leitura/escrita para o início do arquivo.

(6)

6

fseek(FILE *fp, desloc, ref)

Posiciona o ponteiro de acesso em uma posição qualquer da sequência de bytes que constitui o arquivo, onde desloc é a quantidade de bytes a ser avançada (positiva) ou recuada (negativa) e ref é uma referência cujo significado é dado na Tabela

T3.

Tabela T2: Comandos de acesso aos dados. Referência Significado

SEEK_SET Início do arquivo. SEEK_CUR Posição atual. SEEK_END Fim do arquivo.

Tabela T3: Significados de referência. PT9: Escreva um programa que solicite ao usuário 5 números reais e os armazene em arquivo.Em seguida deve solicitar ao usuário que digite um número entre 1 e 5 e mostrar qual o valor que foi introduzido nesta ordem. Deverá, também, mostrar o primeiro e o último elemento do arquivo.

Exemplo:

Introd. o 1-esimo no.:1.2 Introd. o 2-esimo no.:2.3 Introd. o 3-esimo no.:3.4 Introd. o 4-esimo no.:4.5 Introd. o 5-esimo no.:5.6 Qual a ordem do no. 1...5: 2 O 2. valor foi: 2.3 O 1. valor foi: 1.2 O ultimo foi: 5.6 #include <stdio.h> #include <stdlib.h> main() { FILE *fp; int i, n; float v[10], x;

// Lendo dados do teclado. for (i=0; i<5; i++)

{

printf(“Introd. %d-esimo no:”,i+1); scanf(“%f”,&v[i]);

}

// Abrir o arquivo DATA.BIN

if ( (fp = fopen(“DATA.BIN”, “w+b”)) == NULL)

{

printf(“Nao foi possivel criar arquivo”); exit(1);

}

if (fwrite(v, sizeof(int), 5, fp) != 5)

printf(“Nao escreveu todos os elementos”);

else {

printf(“\n Qual a ordem do no. 1-5?”); scanf("%d",&n);

// Mostra o n-ésimo número.

fseek(fp, (long) (n-1)*sizeof(float), SEEK_SET);

fread(&x, sizeof(float),1,fp);

printf(“\n O %d valor foi %f\n”,n,x);

// Mostrar o primeiro valor. rewind(fp);

fread(&x,sizeof(float),1,fp);

printf(“\n O 1. valor foi %f \n”,x);

// Mostrar o último valor.

fseek(fp, -(long) (1)*sizeof(float), SEEK_END);

fread(&x, sizeof(float),1,fp);

printf(“\n O ultimo valor foi %f\n”, x);

}

// Fechando o arquivo. fclose(fp);

}

PE8: Armazenar e depois recuperar as

informações de um cadastro de pessoas. Para tanto, você deverá criar um vetor cujos elementos são do tipo PESSOA tal como definido abaixo:

typedef struct PESSOA

{ char nome[100]; char sexo; int rg;

char end[200]; } PESSOA;

PE9: Aperfeiçoar o PE8 incluindo um

menu com as seguintes opções: 1 – Criar novo arquivo de dados. 2 – Acessar arquivo de dados.

Se o usuário escolher a opção 1, então, serão fornecidas informações de pessoas até a tecla <enter> ser pressionada no campo nome de uma dada pessoa. Se o usuário escolher a opção 2, então, deverão existir duas opções: mostrar todos os dados ou pedir um número que corresponde a posição que um dado ocupa e mostrar esse dado.

Referências

Documentos relacionados

Por isso, respondendo a Heurgon acerca de sua tese, Le Goff sinalizou que em função de suas leituras, havia conquistado certa familiaridade com o conjunto da Idade Média,

Para reverter essa situa~ão, o setor tel que se tornar aais eficiente e versátil no trata.ento dos recursos florestais.. Pelas suas características tecnológicas, as quais perlitel

Our contributions are: a set of guidelines that provide meaning to the different modelling elements of SysML used during the design of systems; the individual formal semantics for

Para uma informação adicional, deve solicitar esclarecimentos junto de um colaborador.. ilustração:

Mesmo com suas ativas participações na luta política, as mulheres militantes carregavam consigo o signo do preconceito existente para com elas por parte não somente dos militares,

Assim, em pacientes com DPOC, apesar da observação de que o número de células satélites está inalterado no músculo do membro estudado em comparação com os controles, as

A apixaba- na reduziu o risco de AVE e embolismo sistêmico em mais de 50%: houve 51 eventos entre os pacientes do grupo apixabana versus 113 no grupo do AAS

vias aéreas) Pinsp (cmH2O) Pressão inspiratória Pmédia (cmH2O) Pressão média das vias aéreas Ppico (cmH2O) Pressão média das vias aéreas Pplatô (cmH2O) Pressão ao final