Departamento de Ciência da
Computação - IME - USP
Até agora, todos os programas feitos nesta disciplina lêem dados do teclado (entrada padrão) e escrevem na tela do monitor (saída padrão). Aqui é mostrado como um programa em C lê dados de um arquivo que está no "disco" (HD, PENDRIVE, . . .) e como grava um arquivo no "disco". Um tratamento profundo do assunto, discutido brevemente aqui, pode ser encontrado no livro:
The C programming language
Brian W. Kernigham e Dennis M. Ritchie
Printice-Hall
Um string é uma seqüência de caracteres terminada pelo caractere especial '\0'. Um string é armazenado em um vetor de caracteres. Por exemplo, o trecho de programa abaixo armazena no vetor nome o string poli\0. Note que é preciso que o tamanho do vetor nome seja pelo menos 5 para armazenar, além dos 4 caracteres da palavra "poli", o caractere especial '\0'. No exemplo, o vetor tem tamanho 6 e o caractere nome[5] não foi utilizado.
char nome[6]; [...] nome[0] = 'p'; nome[1] = 'o'; nome[2] = 'l'; nome[3] = 'i'; nome[4] = '\0'; [...]Para imprimir um string, podemos usar o comando printf com %s. O caractere especial '\0' não é impresso.
[...] printf("%s\n", nome); [...]Para ler um string, podemos usar o comando scanf com %s. O caractere especial '\0' é acrescentado automaticamente ao vetor de caracteres.
[...] scanf("%s", nome); [...]Cuidado que, como um dos parâmetros do scanf é o vetor nome, não há & antes do nome, como ocorre sempre na chamada de uma função que tem um vetor como parâmetro.
Um cuidado especial deve ser tomado quando um string é lido. Embora um string possa conter normalmente o caractere ' ' (espaço), a leitura de um string via scanf é encerrada quando um espaço em branco é encontrado. Portanto, não usem espaços nos nomes dos arquivos a serem lidos no EP.
Um pouco mais sobre strings pode ser visto na página Cadeias de caracteres (strings) escrita por Paulo Feofiloff.
Neste ponto tratamos a seguinte questão:
Como fazer que um arquivo em disco, que tem o seu nome externo ao programa, é associado a algum objeto ou variável que é interna ou conhecida do nosso programa?A regra é clara (como diria o Arnaldo Cézar Coelho :-) ). Antes que possa ser lido ou gravado um arquivo deve ser aberto pela função de biblioteca fopen. A função fopen associa o nome de uma arquivo externo ao programa a uma variável do programa. Isto é feito da seguinte maneira
FILE *arq_texto; char nome[128]; [...] /* o nome a ser digitado não pode conter espaços em branco */ printf("Digite o nome do arquivo para leitura de dados: "); scanf("%s", nome); arq_texto = fopen(nome, "r"); [...]O primeiro parâmetro da função fopen é um string contendo o nome do arquivo externo. Já o segundo parâmetro, que também é um string, indica o modo como se pretende usar o arquivo: leitura ("r"), gravação ("w"), anexação ("a"). Por exemplo o comando
FILE *arq_ent; char nome[128]; [...] printf("Digite o nome do arquivo para leitura de dados: "); scanf("%s", nome); arq_ent = fopen(nome, "r"); if (arq_ent == NULL) { printf("Um erro ocorreu ao tentar abrir o arquivo %s.\n", nome); return 1; /* abandona a execucao do programa */ } [...]associa à variável arq_ent do nosso programa o arquivo em disco correspondente ao nome que foi digitado. O arquivo de nome nome deve estar na mesma pasta (diretório, folder) que o nosso programa, digamos, o ep4.exe. O arquivo é aberto para leitura ("r" de read). Se ocorrer um erro, como tentar associar arq_ent a um arquivo que não existe, fopen retorna o valor representado pela constante NULL.
Se um arquivo que não existe no disco for aberto para escrita, ele é criado. Por exemplo, o seguinte trecho de código cria um arquivo:
FILE *arq_saida; char nome[128]; [...] printf("Digite o nome do arquivo para impressao de dados: "); scanf("%s", nome); arq_saida = fopen(nome, "w"); if (arq_saida == NULL) { printf("Um erro ocorreu ao tentar criar o arquivo %s.\n", nome); return 1; /* abandona a execucao do programa */ } [...]O arquivo de nome nome é criado na mesma pasta/diretório que o arquivo que contém o nosso programa. Se o arquivo já existe ele é destruído e um novo arquivo com o mesmo nome é criado. O arquivo é aberto para escrita ("w" de write).
Sempre que um erro ocorre durante a abertura de um arquivo o valor devolvido pela função fopen é NULL.
O próximo passo é saber como ler os dados de uma arquivo. Considere que um arquivo foi associado à variável arq_ent do nosso programa. O comando
FILE *arq_ent; char nome[128]; [...] arq_ent = fopen(nome, "r"); [...] fscanf(arq_ent, "%d", &matriz[i][j]); [...]lê um número inteiro do arquivo da mesma maneira que
[...] scanf("%d", &num); [...]lê um número digitado através do teclado. Na verdade, o comando
scanf("%d",&num);é uma abreviatura do comando
fscanf(stdin, "%d", &num);onde stdin é a entrada padrão, que no nosso caso, é o teclado.
Para escrever-se em um arquivo pode-se usar os seguintes comandos
FILE *arq_sai; char nome[128]; [...] arq_sai = fopen(nome, "w"); [...] fprintf(arq_sai, "arquivo de saida\n"); fprintf(arq_sai, "%d %d\n", no_colunas, no_linhas); [...]O primeiro fprintf escreve o texto "arquivo de saida\n" no arquivo e o segundo fprintf escreve o conteúdo da variável no_colunas um espaco (" "), o conteúdo da variável no_linhas e um barra-n ("\n") para mudar de linha. Veja um exemplo um pouco mais elaborado:
#define MAX 800 FILE *arq_sai; char nome[128]; int matriz[MAX][MAX]; int no_linhas; /* numero de linhas da matriz */ int no_colunas; /* numero de colunas da matriz */ [...] arq_sai = fopen(nome, "w"); if (arq_sai == NULL) { printf("Um erro ocorreu ao tentar criar o arquivo %s.\n", nome); return 1; /* abandona a execucao do programa */ } [...] fprintf(arq_sai, "arquivo de saida\n"); fprintf(arq_sai, "%d %d\n", no_colunas, no_linhas); [...] /* escreva matriz no arquivo */ for (i = 0; i < no_linhas; i++) { for (j = 0; j < no_colunas; j++) { fprintf(arq_sai, " %d ", matriz[i][j]); } fprintf(arq_sai, "\n"); } [...]
De maneira semelhante ao que ocorre com o scanf, o comando
printf("%d\n", matriz[i][j]);é uma abreviatura do comando
fprintf(stdout, "%d\n", matriz[i][j]);onde stdout é a saída padrão, que no nosso caso, é a tela do monitor.
fclose(arq);
FILE *arq_ent; char nome[128]; char ch; [...] printf("Digite o nome do arquivo para leitura de dados: "); scanf("%s", nome); arq_ent = fopen(nome, "r"); if (arq_ent == NULL) { printf("Um erro ocorreu ao tentar abrir o arquivo %s.\n", nome); return 1; /* abandona a execucao do programa */ } fscanf(arq_ent,"%c", &ch); while (feof(arq_ent) == 0) /* enquanto nao terminou o arquivo */ { printf("%c", ch); fscanf(arq_ent,"%c", &ch); } fclose(arq_ent); [...]
/* * Programa que que faz uma copia de uma matriz em um arquivo * de nome original.dat para um arquivo de nome copia.dat. O * arquivo copia.dat ficara no mesmo diretorio do arquivo * original.dat. * */ #include <stdio.h> #define MAX 1000 int main() { FILE *arq_o; /* associado ao arquivo original */ char nome_o[128]; /* armazena o nome do arquivo original */ FILE *arq_c; /* associado ao arquivo copia */ char nome_c[128]; /* armazena o nome do arquivo copia */ int m; /* numero de linhas da matriz */ int n; /* numero de colunas da matriz */ int i, j; /* indices da matriz */ int matriz[MAX][MAX]; /* 1. leia o nome do arquivo original */ printf("Digite o nome do arquivo original: "); /* Neste exemplo, digite "original.dat" */ scanf("%s", nome_o); /* 2. abra arquivo original.dat para leitura */ arq_o = fopen(nome_o, "r"); if (arq_o == NULL) { printf("Erro na abertura do arquivo %s.\n", nome_o); return 1; /* abandona a execucao do programa */ } /* 3. leia o nome do arquivo copia */ printf("Digite o nome do arquivo copia: "); /* Neste exemplo, digite "copia.dat" */ scanf("%s", nome_c); /* 4. abra arquivo copia.dat para escrita */ arq_c = fopen(nome_c, "w"); if (arq_c == NULL) { printf("Erro na abertura do arquivo %s.\n", nome_c); fclose(arq_o); /* feche o arquivo original.dat */ return 1; /* abandona a execucao do programa */ } /* 5. leia as dimensoes da matriz do arquivo original.dat */ fscanf(arq_o, "%d %d", &m, &n); /* 6. escreva as dimensoes da matriz no arquivo copia.dat */ fprintf(arq_c, "%d %d\n", m, n); /* 7. leia a matriz do arquivo original.dat */ for (i = 0; i < m; i++) { /* leia a linha i */ for (j = 0; j < n; j++) { fscanf(arq_o, "%d", &matriz[i][j]); } } /* 8. escreva a matriz no arquivo copia.dat */ for (i = 0; i < m; i++) { /* escreva a linha i */ for (j = 0; j < n; j++) { fprintf(arq_c, "%d ", matriz[i][j]); } fprintf(arq_c, "\n"); } /* 9. feche o arquivo original.dat */ fclose(arq_o); /* 10. feche o arquivo copia.dat */ fclose(arq_c); return 0; }
EXERCICIO. Reescreva o programa acima sem usar uma matriz. É necessário limitar a dimensão da matriz?