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?