Curso de C - 11. Trabalhando com Arquivos

Curso do C - 11. Trabalhando com arquivos

De nada adianta desenvolvermos programas que fazem várias coisas se, ao final de sua execução, todos os dados são perdidos. Vamos aprender nesta aula como manipular arquivos em C. Focaremos nosso aprendizado nas funções do padrão ANSI C, como vem sendo feito com os outros tópicos.

A linguagem C trabalha com arquivos através de uma abstração chamada stream. Imagine a stream como se fosse um canal, onde você grava, ou de onde você lê os dados. Esse tipo de abstração dá maior flexibilidade à linguagem, pois podemos manipular não só arquivos, mas outros dispositivos. Já fizemos isso. Lembra do fgets e do stdin? O stdin é uma stream padrão, que não direciona para um arquivo, mas para o console. Nós trabalhamos com arquivos da mesma forma que trabalhamos com a stdin. Essa é a vantagem das streams. Não importa quem está do outro lado, o modo de manipular os dados é o mesmo.

Existem dois tipos de streams: a stream texto e a binária. A stream texto é uma sequência de caracteres (arquivos texto), onde cada linha possui um caractere de nova linha. A stream binária é uma sequência de bytes.

As funções para manipulação de arquivos em C estão incluídas no cabeçalho stdio.h.

11.1. Abrindo e Fechando um arquivo

Para poder trabalhar com um arquivo em C, devemos primeiro abrí-lo. A função que realiza a abertura do arquivo é a fopen(). Ela retorna um ponteiro para o arquivo, do tipo FILE. Se não for possível abrir o arquivo, retornará NULL.

A função fopen() aceita apenas 2 argumentos, o nome do arquivo e uma string que define o modo como o arquivo será aberto (modo texto, modo binário, para leitura, para gravação, etc.). Seu protótipo é o seguinte:

  FILE *fopen(const char *nome, const char *modo);

O tipo FILE está definido no cabeçalho stdio.h e armazena informações sobre o arquivo, como nome, posição atual, status, etc. Vamos ver um exemplo da abertura de um arquivo:

  FILE *arq;	/* ponteiro para arquivo */
  
  arq= fopen("aula.dat", "w");
  
  if (!arq)
  	printf("Erro ao abrir arquivo.");

Aqui aula.dat é criado em modo texto e para gravação. É importante sempre testar se o arquivo foi aberto corretamente, através do if acima.

Segue abaixo uma lista dos modos de abertura dos arquivos em C:

Modo Descrição
r abrir arquivo texto para leitura
r+ abrir arquivo texto para leitura ou escrita
w criar um arquivo texto para escrita
w+ criar um arquivo texto para leitura ou escrita
a anexar a um arquivo texto
a+ anexar a um arquivo texto para leitura ou escrita
rb abrir arquivo binário para leitura
r+b abrir arquivo binário para leitura ou escrita
wb abrir ou criar arquivo binário para escrita
w+b abrir ou criar arquivo binário para leitura ou escrita
ab anexar a um arquivo binário
a+b anexar a um arquivo binário para leitura ou escrita

Ao criar um arquivo com permissão para escrita, como no exemplo, será apagado qualquer arquivo já existente com esse nome e criado outro do zero. Para abrir um arquivo já existente e adicionar os dados ao seu final, utilize o modo a. A opção r abre os arquivos somente para leitura.

Fechar um arquivo é muito fácil... Quando fechamos um arquivo, todos os dados que estão no buffer são gravados para o arquivo e depois ele é fechado. A função fclose() aceita como argumento apenas o ponteiro para o arquivo. Seu protótipo é:

  int fclose(FILE *arq);

Se correr tudo bem ao fechar o arquivo, é retornado zero. Outro valor indica erro, como disco cheio, por exemplo. Exemplo:

  #include <stdio.h>

  
  main()
  {
  	FILE *arq;
  	
  	arq= fopen("aula.dat", "w");
  	
  	if (!arq)
  	{	
  		printf("Erro ao criar arquivo!");
  		return 1;
  	}
  	else
  		printf("Arquivo aula.dat criado.");
  	
  	fclose(arq);	/* fechando o arquivo */
  	return 0;
  }

11.2. Lendo e Escrevendo Caracteres

Para escrever um caractere em um arquivo, podemos utilizar duas funções: putc() ou fputc(). As duas são idênticas, e são mantidas para preservar a compatibilidade com as versões mais antigas da linguagem. A forma geral é:

  putc(caractere, ponteiro_arquivo);

ou

  fputc(caractere, ponteiro_arquivo);

Exemplo:

  #include <stdio.h>
  
  main()
  {
  	FILE *arq;
  	char ch;
  	
  	arq= fopen("aula.dat", "w");
  	if (!arq)
  	{
  		printf("Erro ao abrir arquivo!");
  		return 1;
  	}
  	
  	printf("Digite um caractere: ");
  	scanf("%c", &ch);
  	
  	fputc(ch, arq);		/* grava o caractere lido no arquivo */
  	fclose(arq);
  	return 0;
  }

Depois de executar esse programa, abra o arquivo aula.dat em algum editor de textos e você verá o caractere no arquivo.

Ler um caractere de um arquivo também é fácil. Podemos usar duas funções: getc() ou fgetc(). As duas também são idênticas e são mantidas para preservar a compatibilidade com as versões mais antigas da linguagem.

Forma geral:

  ch= fgetc(ponteiro_arquivo);

ou

  ch= getc(ponteiro_arquivo);

Exemplo:

  #include <stdio.h>
  
  main()
  {
  	FILE *arq;
  	char ch;
  	
  	arq= fopen("aula.dat", "r");	/* abre em modo leitura */
  	if (!arq)
  	{
  		printf("Erro ao abrir arquivo!");
  		return 1;
  	}
  	
  	ch= fgetc(arq);		/* lê o caractere do arquivo */
  	printf("%c", ch);	/* imprime na tela */
  	
  	fclose(arq);
  	return 0;
  }

Abrimos o mesmo arquivo, aula.dat, só que em modo leitura, e lemos o caractere gravado anteriormente, imprimindo na tela. Quando o final do arquivo é alcançado, a função fgetc() (ou getc()) devolve EOF (indicador de fim de arquivo).

Você pode usar o indicador EOF em uma condição para fazer o programa terminar quando for o fim do arquivo. Exemplo:

  #include <stdio.h>

  
  main()
  {
  	FILE *arq;
  	char nome[20];
  	char ch;
  	
  	printf("Digite o nome do arquivo-texto: ");
  	gets(nome);	/* usando gets() mesmo, só para exemplificar. */ 
  	
  	arq= fopen(nome, "r");
  	if (!arq)
  	{
  		printf("Erro ao abrir arquivo!");
  		return 1;
  	}
  	
  	do
  	{
  		ch= fgetc(arq);
  		putchar(ch);
  	} while (ch != EOF); /* só para quando encontrar o fim do arquivo */ 
  	
  	fclose(arq);
  	return 0;
  }

Aqui o usuário digita o nome do arquivo-texto, e este é escoado para a tela. Vamos aprender agora como passar argumentos para o programa pela linha de comando, para facilitar operações deste tipo.

11.3. Passando argumentos pela linha de comando

O programa acima lembra um pouco o cat do Linux ou o type do DOS. Qual a diferença? Nesses dois programas, o nome do arquivo é passado como argumento junto com o nome do executável, na linha de comando. Assim:


  cat arquivo.c

Podemos fazer o mesmo em nossos programas, passando dois argumentos para a função main(): argc e argv.

O parâmetro argc é um inteiro e armazena o número de argumentos que são passados pela linha de comando. Se não for passado nenhum argumento, argc será 1, pois o nome do programa é incluído nesta contagem.

O parâmetro argv é um ponteiro para uma matriz de ponteiros para caractere, ou um ponteiro para uma matriz de strings. Ele aponta para todos os argumentos passados pela linha de comando (cada elemento da matriz é um argumento). Como todos os argumentos são strings, se você precisar manipular números passados como argumentos, por exemplo, você precisará convertê-los para o tipo apropriado.

Vamos ver um exemplo:

  #include <stdio.h>
  
  main(int argc, char *argv[])	/* os dois parâmetros especiais */
  {
  	int i;
  
  	if (argc < 2)
  		printf("O programa %s não possui argumentos na linha de comando.", argv[0]);
  	else
  	{
  		printf("O programa possui %d argumentos: ", argc-1);
  		for (i=1; i<argc; i++)
  			printf("%s\n", argv[i]);
  	}
  	return 0;
  }

Neste exemplo, primeiro testamos argc. Se ele tiver valor menor que 2 (1), imprimimos uma mensagem dizendo que não foram passados argumentos pela linha de comando. Caso contrário, imprimimos o número de argumentos passados (sem contar o programa) e imprimimos também cada argumento, através do for.

Com esses recursos em mãos, podemos modificar o programa do tópico 11.2 para trabalhar da mesma forma que o cat do Linux ou o type do DOS:

  /* mycat.c */
  #include <stdio.h>

  
  main(int argc, char *argv[])
  {
  	FILE *arq;
  	char ch;
  	
  	if (argc != 2)
  	{
  		printf("Uso: %s <nome arquivo>\n", argv[0], argv[1]);
  		return 1;
  	}
  	
  	arq= fopen(argv[1], "r");
  	if (!arq)
  	{
  		printf("Erro ao abrir arquivo!");
  		return 1;
  	}
  	
  	do
  	{
  		ch= fgetc(arq);
  		putchar(ch);
  	} while (ch != EOF); /* só para quando encontrar o fim do arquivo */ 
  	
  	fclose(arq);
  	return 0;
  }

Depois faça um teste com esse programa. Você vai ver que seu modo de trabalhar é idêntico ao cat do Linux ou o type do DOS.

11.4. Detectando o fim do arquivo

Já usamos EOF para detectar o fim de um arquivo-texto, no exemplo acima. Em arquivos binários, porém, pode acontecer de algum dado do arquivo possuir valor igual ao do inteiro EOF, o que confundiria o programa. Para evitar essa inconsistência, devemos utilizar a função feof(), que retorna verdadeiro quando o final do arquivo é atingido. Exemplo:

  do
  {
  	ch= fgetc(arq);
  	putchar(ch);
  } while (!feof(arq)); /* só para quando encontrar o fim do arquivo */ 

11.5. Lendo e gravando strings em arquivos

Para ler e gravar strings em arquivos, temos duas funções: fputs(), que grava a string no arquivo, e fgets(), nossa velha conhecida, que lê uma string de um arquivo.

A função fputs() é similar a puts(), mas grava a string em um arquivo. Sua forma geral é:

  fputs(string, arq);

Onde string é a string em si e arq é o ponteiro descritor do arquivo. Exemplo:

  #include <stdio.h>

  
  main()
  {
  	FILE *arq;
  	char string[30];
  	
  	arq= fopen("dados.dat", "w");
  	if (!arq)
  	{
  		printf("Não foi possível criar arquivo!");
  		return 1;
  	}
  	printf("Digite uma string: ");
  	gets(string);		/* aqui pode ... */
  	fputs(string, arq);	/* grava a string lida no arquivo */
  	fclose(arq);
  	return 0;
  }

Agora abra o arquivo criado no programa em algum editor de textos e você verá a string digitada...

A função fgets() já é nossa conhecida... Usamos ela para ler strings do console, mas ela também é usada para ler strings de um arquivo. Ela lê a string até achar um caractere de nova linha ou até que tamanho-1 caracteres tenham sido lidos. Quando um caractere de nova linha é encontrado (\n) ele passa a ser parte da string, que é terminada por nulo (\0). Forma geral:

  fgets(string, tamanho, arq);

Exemplo:

  #include <stdio.h>
  
  main()
  {
  	FILE *arq;
  	char string[30];
  	
  	arq= fopen("dados.dat", "r");
  	if (!arq)
  	{
  		printf("Erro ao abrir arquivo!");
  		return 1;
  	}
  	while (!feof(arq)) 
  	{
  		fgets(string, 20, arq);		/* lê do arquivo */
  		puts(string);			/* imprime na tela */
  	}
  	fclose(arq);
  	return 0;
  }

11.6. Lendo e escrevendo com fread() e fwrite()

As funções fread() e fwrite() possibilitam a leitura e gravação de qualquer tipo de dado. São utilizadas principalmente para ler e gravar dados definidos pelo usuário, como estruturas. Os protótipos das duas funções são os seguintes:

  size_t fread(void *ponteiro, size_t bytes, size_t count, FILE *arq);

  size_t fwrite(const void *ponteiro, size_t bytes, size_t count, FILE *arq);

fread() retorna o número de dados lidos do arquivo (size_t é um número inteiro). O primeiro argumento, void *ponteiro, é um ponteiro para o dado, ou a variável. O segundo argumento, size_t bytes, é o tamanho do dado a ser lido em bytes (geralmente especificado através de sizeof). O terceiro argumento, size_t count, é o número de dados de tamanho bytes que será lido do arquivo. O quarto argumento, FILE *arq, é o ponteiro descritor do arquivo.

fwrite() retorna o número de dados gravados no arquivo. O primeiro argumento, void *ponteiro, é um ponteiro para o dado, ou a variável. O segundo argumento, size_t bytes, é o tamanho do dado a ser gravado em bytes (geralmente especificado através de sizeof). O terceiro argumento, size_t count, é o número de dados de tamanho bytes que será gravado no arquivo. O quarto argumento, FILE *arq, é o ponteiro descritor do arquivo.

Vamos demonstrar as duas funções através de exemplos:

  /* Vamos gravar dados em um arquivo através da função fwrite() */
  #include <stdio.h>
  
  struct meudado			/* definição da estrutura */
  {
  	char nome[20];
  	long int fone;
  };
  
  typedef struct meudado Agenda;	/* criamos o tipo Agenda */
  
  main()
  {
  	Agenda dado;	/* declaração da variável do tipo Agenda */
  	FILE *arq;
  	char flag= 'y';
  	
  	arq= fopen("agenda.dat", "a+b");	   /* abrimos para anexar, binário */ 
  	if (!arq)
  	{
  		printf("Erro ao abrir arquivo!");
  		return 1;
  	}
  	
  	printf("*** Agenda -  Gravar Dado ***\n");
  	while (flag != 'n')
  	{
  		printf("Nome: ");
  		fgets(dado.nome, 20, stdin);	/* estamos lendo do console */
  		printf("Fone: ");
  		scanf("%ld%*c", &dado.fone);
  		
  		/* grava a estrutura no arquivo */
  		fwrite(&dado, sizeof(Agenda), 1, arq);
  		printf("Deseja gravar mais dados (s/n)? ");
  		scanf("%c%*c", &flag);
  	}
  	fclose(arq);
  	return 0;
  }

Neste exemplo demonstramos o uso de fwrite() gravando uma estrutura para arquivo. Agora faremos um programa que lê o conteúdo deste mesmo arquivo e exibe os dados na tela, com o uso de fread():

  #include <stdio.h>
  
  struct meudado			/* definição da estrutura */
  {
  	char nome[20];
  	long int fone;
  };
  
  typedef struct meudado Agenda;	/* criamos o tipo Agenda */
  
  main()
  {
  	Agenda dado;	/* declaração da variável do tipo Agenda */
  	FILE *arq;
  
  	arq= fopen("agenda.dat", "rb");	/* abrimos arquivo binário, modo leitura */
  	if (!arq)
  	{
  		printf("Erro ao abrir arquivo!");
  		return 1;
  	}
  	
  	printf("*** Agenda -  Relatório ***\n");
  	
  	while (!feof(arq))	/* enquanto não for o fim do arquivo... */
  	{
  		/* o dado é lido e armazenado na estrutura */
  		fread(&dado, sizeof(Agenda), 1, arq);
  		printf("Nome: %s", dado.nome);
  		printf("Fone: %ld\n\n", dado.fone);
  	}
  	fclose(arq);
  	return 0;
  }

Aqui listamos todos os dados armazenados no arquivo agenda.dat, gravados antes pelo outro programa.

11.7. Reposicionando o indicador de posição

Quando um dado é gravado em um arquivo, o indicador de posição é movido para o fim da gravação deste dado no arquivo, ou seja, ele fica no lugar onde um próximo eventual dado será gravado. Muitas vezes, porém, é desejável que esse indicador de posição seja movido para o início do arquivo, para que os dados gravados até então sejam lidos. A função rewind() realiza essa façanha, movendo o indicador de posição do arquivo para o seu início. Protótipo:

  void rewind(FILE *arq);

Vamos ver um exemplo:

  #include <stdio.h>
  
  main()
  {
  	char ch;
  	int i;
  	FILE *arq;
  	
  	/* abrir em modo leitura/escrita */
  	arq= fopen("teste.txt", "w+");
  	if (!arq)
  	{
  		printf("Erro ao abrir arquivo!");
  		return 1;
  	}
  	
  	/* gravaremos 10 caracteres no arquivo */
  	for (i=0; i<10; i++)
  	{
  		printf("Digite um caractere: ");
  		scanf("%c%*c", &ch);
  		fputc(ch, arq);
  	}
  	
  	/* movemos o indicador de posição para o início do arquivo */
  	rewind(arq);
  		
  	/* agora podemos ler do arquivo os 10 caracteres digitados */
  	ch= fgetc(arq);
  	do
  	{
  		printf("%c\n", ch);
  		ch= fgetc(arq);
  	} while(!feof(arq));
  	
  	fclose(arq);
  	return 0;
  } 	

11.8. Tratando erros com ferror()

A função ferror() retorna verdadeiro se ocorreu um erro em uma operação com arquivo, e falso se não ocorreu. Protótipo:

  int ferror(FILE *arq);

Exemplo:

  	do
  	{
  		printf("%c\n", ch);
  		ch= fgetc(arq);
  		if (ferror(arq))
  		{
  			printf("Erro ao ler caractere.");
  			return 1;
  		}
  	} while(!feof(arq));

Usamos um trecho do programa anterior para adicionar a função ferror() para tratar eventuais erros. Esta função pode ser usada em qualquer operação de leitura ou escrita em arquivos.

11.9. Esvaziando a stream

A função fflush() descarrega o conteúdo do buffer da stream para o arquivo, esvaziando-a. Protótipo:

  int fflush(FILE *arq);

O valor 0 é retornado em caso de sucesso, e EOF em caso de falha.

11.10. Removendo arquivos

Para remover um arquivo temos a função remove(). Esta função retorna zero para sucesso e diferente de zero para falha na remoção do arquivo.

Protótipo:

  int remove(const char *arquivo);

Exemplo:


  #include <stdio.h>
  
  main(int argc, char *argv[])
  {
  	int aux;
  	
  	if (argc != 2)
  	{
  		printf("Uso: %s <arquivo a excluir>\n", argv[0]);
  		return 1;
  	}
  	
  	aux= remove(argv[1]);
  	if (aux)
  	{
  		printf("Não foi possível remover o arquivo!");
  		return 1;
  	}
  	
  	return 0;
  }

O programa acima é similar ao rm do Linux. Basta digitar o nome do arquivo a excluir junto com o nome do programa e o arquivo será excluído, se existir. O único argumento aceito pela função remove() é o nome do arquivo a excluir. Neste caso, não é necessário abrir o arquivo.

11.11. Leitura e Gravação com fprintf() e fscanf()

As funções fprintf() e fscanf() são utilizadas para ler e gravar em arquivos da mesma forma que as funções printf() e scanf() fazem no console. O funcionamento é o mesmo, bastando apenas colocar como primeiro argumento das funções o ponteiro descritor do arquivo.

Protótipos de fprintf() e fscanf():

  int fprintf(FILE *arq, const char *string_de_controle, ...);

  int fscanf(FILE *arq, const char *string_de_controle, ...);

Um exemplo para ilustrar:

  #include <stdio.h>

  
  main()
  {
  	int num, aux;
  	FILE *arq;
  	
  	arq= fopen("teste.txt", "w+");
  	if (!arq)
  	{
  		printf("Erro ao abrir arquivo!");
  		return 1;
  	}
  	
  	num= 5;
  	
  	/* grava um inteiro no arquivo */
  	fprintf(arq, "%d\n", num);
  	
  	/* move indicador de posição para início do arquivo */
  	rewind(arq);
  	
  	/* lê o inteiro do arquivo e guarda em aux */
  	fscanf(arq, "%d", &aux);
  	
  	/* imprime aux */
  	printf("%d ", aux);
  	fclose(arq);
  	return 0;
  }

Essas duas funções perdem em desempenho para fread() e fwrite(), visto que os dados são formatados em modo ASCII (como apareceriam na tela) e não em binário.

11.12. Acesso Aleatório em arquivos

Até agora nós gravamos e lemos de forma sequencial, do início até a posição onde queremos. Mas essa é uma forma de acesso ineficiente para muitos problemas de programação. Para que ficar passando de dado em dado se podemos ir direto aonde queremos? É para isso que existem as funções fseek() e ftell().

A função fseek() move o indicador de posição do arquivo até a posição fornecida como argumento na função. Desta forma, podemos acessar o décimo registro de um arquivo, por exemplo, sem ter que ler os anteriores, indo diretamente até ele. Seu protótipo é:

  int fseek(FILE *arq, long bytes, int origem);

O primeiro argumento é o ponteiro descritor do arquivo; o segundo argumento é o número de bytes, a partir de origem, que será a nova posição do indicador; o terceiro argumento, origem, pode ser uma das seguintes opções:

Macro Origem
SEEK_SET início do arquivo
SEEK_CUR posição corrente
SEEK_END final do arquivo

A função ftell() retorna o número de bytes do arquivo do começo até a posição atual. Ela é útil quando queremos saber quantos registros foram gravados em um arquivo. Protótipo:

  long ftell(FILE *arq);

Vamos ver um exemplo:

  #include <stdio.h>
  
  struct dado
  {
  	int id;
  	float preco;
  };
  
  typedef struct dado Tdado;	/* criamos o tipo Tdado */
  
  main()
  {
  	int i, id;
  	char flag;
  	FILE *arq;
  	Tdado produto;
  	
  	/* criamos o arquivo binário */
  	arq= fopen("produtos.dat", "wb");
  	if (!arq)
  	{
  		printf("Erro ao abrir arquivo!");
  		return 1;
  	}
  	
  	/* vamos ler 10 registros (de 0 a 9) */
  	for (i=0; i<10; i++)
  	{
  		produto.id= i;
  		printf("Digite o preço do produto %d: ", i);
  		scanf("%f%*c", &produto.preco);
  		
  		/* grava a estrutura no arquivo */
  		fwrite(&produto, sizeof(Tdado), 1, arq);
  	}
  	fclose(arq);	/* fecha o arquivo */
  	
  	/* agora, reabrimos o arquivo para leitura */
  	arq= fopen("produtos.dat", "rb");
  	if (!arq)
  	{
  		printf("Erro ao abrir arquivo!");
  		return 1;
  	}
  	
  	do
  	{
  		printf("Digite o número do registro do produto: ");
  		scanf("%d%*c", &id);
  		
  		if ((id > 9) || (id < 0))
  			continue;
  			
  		/* Posicionamos o indicador. O número de bytes é calculado com
  		   id * sizeof(Tdado) */
  		fseek(arq,(long)id * sizeof(Tdado), SEEK_SET);
  		
  		/* lemos o dado */
  		fread(&produto, sizeof(Tdado), 1, arq);
  		
  		/* imprimimos na tela */
  		printf("ID: %d\n", produto.id);
  		printf("Preço: %.2f\n\n", produto.preco);
  		
  		printf("Deseja consultar mais produtos (s/n)? ");
  		scanf("%c%*c", &flag);
  	} while (flag != 'n');
  	
  	fclose(arq);
  	return 0;
  }

Neste programa, o usuário digita o preço de 10 produtos (de 0 a 9), que são gravados em um arquivo binário. Esse arquivo é fechado e reaberto em modo leitura, e o usuário deve digitar o número do registro (qualquer número de 0 a 9). Quando o usuário digita o número do registro, o indicador de posição é movido pela função fseek() para o local onde o dado foi gravado; este dado é lido e impresso na tela. Este ciclo só termina quando o usuário digita 'n' (não quer mais consultar produtos). Examine este código fonte cuidadosamente e faça o teste de mesa, para o perfeito entendimento.

Suponhamos que, ao invés de digitar 10 preços de produtos, o usuário digitasse o quanto quisesse. Como poderíamos saber quantos registros haveriam no arquivo? É aí que vemos uma utilidade para ftell(). Bastaria posicionar o indicador de posição no final do arquivo:

  fseek(arq, 0, SEEK_END);

fazer uma variável do tipo long (no caso, bytes) receber o número de bytes que o arquivo contém:

  bytes= ftell(arq);

e fazer o cálculo:

  num= bytes/sizeof(Tdado);

OBS: O segundo argumento de fseek() deve, obrigatoriamente, ser do tipo long. Se for um inteiro, devemos usar um modificador de tipo, como fizemos na função fseek(arq,(long)id * sizeof(Tdado), SEEK_SET). O (long) força o resultado da expressão ser do tipo long.

11.13 Streams Padrão

Quando executamos um programa em C, 3 streams são automaticamente abertas: stdin, stdout e stderr. A stdin nós já conhecemos e usamos na função fgets(). Essa stream é a entrada padrão, ou o teclado. A stdout é a saída padrão, ou o console. A stderr é a saída de erros padrão (geralmente o console).

Nós podemos perfeitamente utilizar as funções de manipulação de arquivos para ler e escrever dados no console (assim como fizemos com fgets). Por exemplo, a função fprintf(stdout, "%d", num) escreverá um inteiro no console. Experimente utilizar as outras funções de manipulação de arquivos com estas streams.

Essas 3 streams são abertas automaticamente, portanto você não deve tentar abrí-las e nem tentar fechá-las no final do programa. Elas não são variáveis normais.

Você também pode redirecionar essas streams padrão para um arquivo, usando a função freopen(). Por exemplo, stdout pode-se tornar uma stream para arquivo ao invés do console.

Protótipo de freopen():

  FILE *freopen(const char *nome_arquivo, const char *modo, FILE *stream);

Vamos fazer um exemplo:

  /* este programa redireciona a stream padrão stdout */
  #include <stdio.h>
  
  main()
  {
  	/* stdout passa a apontar para o arquivo Teste */
  	freopen("Teste", "w", stdout);
  	
  	printf("stdout agora está no arquivo Teste\n");
  }

Agora abra o arquivo Teste e veja que a frase impressa por printf() não foi ecoada para o console, mas para esse arquivo.

Utilizar esse redirecionamento é menos eficiente do que usar as rotinas fread() e fwrite().

Você pode redirecionar outras streams, além das streams padrão.

Bem, espero que você tenha se divertido bastante nesta aula... :) Agora, alguns exercícios.


Exercícios

1) Faça um programa que efetue a cópia de um arquivo existente para outro lugar e/ou outro nome. Ele deve funcionar como o programa cp do Linux ou o copy do DOS, assim:

  programa arquivo_origem arquivo_destino

2) Faça um programa de agenda que ofereça um menu para o usuário com as opções Inserir, Listar, Buscar e Sair. O programa deve armazenar os dados (nome, telefone e e-mail) em um arquivo binário.

3) Faça um programa que troque os espaços de um arquivo texto por tabulações. O nome do arquivo deve ser passado como argumento pela linha de comando.

4) Faça um programa que concatene dois arquivos texto, e o arquivo resultante tenha um nome diferente dos dois arquivos usados na concatenação. Use argumentos da linha de comando.


Powered by txt2tags



Esta notícia veio de LinuxDicas - Artigos, Dicas e Notícias Sobre o Mundo Linux
http://www.linuxdicas.com.br

O link desta notícia é:
http://www.linuxdicas.com.br/modules.php?name=Sections&op=viewarticle&artid=222