Curso de C
Arquivos


Você está em: MarMSX >> Cursos >> C   A memória do computador é volátil, e todos os dados contidos nela é perdido após o desligamento do computador.
  Se desejarmos manter os dados de uma aplicação vivos após o desligamento, como por exemplo, o resultado de um jogo ou os nomes de uma agenda telefônica, teremos que salvá-los em disco.
  Existem dois formatos de arquivos: o formato texto e o formato binário.
  Em arquivos no formato texto, os códigos armazenados serão interpretados como valor de entrada na tabela ASCII, de maneira a formar um texto. Assim, por exemplo, o código 65 significa a letra 'A' maiúscula. Além disso, os arquivos no formato texto são divididos em linhas, onde um caracter com um código determinado indica o fim de uma linha.
  Em arquivos binários, os códigos são a representação direta dos dados, em seu formato original. Por exemplo, um inteiro será armazenado em disco como é armazenado na memória, ou seja, com 2 bytes por número. Já o double, em seu formato de 8 bits.
  Fica evidente que o programador deverá conhecer a disposição dos dados e seus respectivos tipos na hora de recuperar a informação no disco. Caso contrário, poderemos recuperar dados de um número double em um variável do tipo inteiro, por exemplo, causando inconsistência nos dados.

  A função em C que abre um arquivo para trabalhar é:
 fopen(<nome_do_arquivo>, <parâmetros_do_arquivo>);
  No qual retorna um ponteiro para uma variável do tipo arquivo (FILE).

  Os parâmetros de abertura de um arquivo são:

  Arquivos do Tipo Texto

  Gravação de Dados em Disco

  A função fprintf é utilizada quando deseja-se enviar uma string para um arquivo de saída. Por exemplo, pode-se gravar uma frase em um arquivo texto da seguinte maneira:
#include <stdio.h>

FILE *fp;

void main(void)
{
    fp = fopen("arquivo.txt","wt");
    fprintf(fp, "O MSX ainda vive!");
    fclose(fp);
} 

  Leitura de Dados em Disco

  A leitura de textos é feita através da função "getc". Essa função lê caractere a caractere. Entretanto, é desejável ler o texto linha a linha.
  O programa abaixo implementa uma função de leitura de linha, a "readln".
#include <stdio.h>

FILE *fp;
char linha[255];

void readln(FILE *fp, char *linha)
{
  char c;
  int p=0;

  while ((c = fgetc(fp)) != EOF)
  {
    if (c == '\n')
      break;

    linha[p++] = c;
  }
}

void main(void)
{
  fp = fopen("arquivo.txt","rt");
  readln(fp, linha);
  fclose(fp);

  printf("%s\n", linha); 
}


  Leitura formatada

  Podemos utilizar a função fscanf para realizar uma leitura formatada dos dados.
  Por exemplo, seja o arquivo formatado a seguir "dados.txt", contendo uma lista de objetos.
 Cachorro
 Gato
 Mesa
 Cadeira
 Salão de jogos
  O programa a seguir irá ler o arquivo e escrever os dados na tela.
#include <stdio.h>

main()
{
	FILE *fp;
	char texto[10];

	fp = fopen("dados.txt", "rt");

	while (fscanf(fp, "%s", texto) != EOF)
		printf("%s\n", texto);
}
  Saída:
  Cachorro
  Gato
  Mesa
  Cadeira
  Salão
  de
  jogos

  A opção de formatação "%s" lê uma string até encontrar um espaço em branco. Para solucionar o problema do "Salão de jogos" escrito em três linhas, podemos utilizar a opção de formatação de string [] ou [^]. A primeira opção irá conter uma lista de caracteres aceitos, enquanto que a segunda uma lista de caracteres não aceitos, e que quando encontrados, termina a formação da string. A esses caracteres que param a formação de uma string chamamos de delimitadores.
  Dessa forma, trocamos a linha:
while (fscanf(fp, "%s", texto) != EOF)
  Por:
while (fscanf(fp, "%[^\n]\n", texto) != EOF)
  No caso do nosso arquivo, o delimitador é o caractere de nova linha "\n". O delimitador deverá ser repetido logo após os colchetes, senão o programa não pára de ler a mesma linha. No caso de arquivos com a terminação de linha no formato do MSX e Windows, utilizar a formatação "%[^\r]\r\n".


  Arquivos do Tipo Binário

  Os arquivos de tipo binário podem ser lidos byte a byte ou por blocos.
  Observa-se que a leitura byte a byte deve ser evitada, pois o acesso ao disco repetidamente é mais caro (leva mais tempo) do que o acesso único, realizado na transferência de dados por bloco.
  Assim, temos as seguintes funções:   Sintaxe do fread / fwrite:
 fread(<variavel>, <tamanho>, <num_leituras_sequenciais>, <arquivo>);
 fwrite(<variavel>, <tamanho>, <num_leituras_sequenciais>, <arquivo>);
  Onde:
  Exemplo de abertura de arquivo binário em bloco:
#include <stdio.h>

FILE *fp;
char buffer[1024];

void main(void)
{
  fp = fopen("exemplo.bin","rb");
  fread(buffer, 1024, 1, fp);
  fseek(fp, 40, SEEK_SET);
  fclose(fp);
}
  Obs: o comando fseek move o ponteiro no arquivo (ver mais detalhes no capítulo de arquivos do Pascal). Sintaxe:
 fseek(<arquivo>, <offset>, <referência>);
  Onde:
  Obs: caso as constantes SEEK_SET, SEEK_CUR e SEEK_END não funcionem, substitua pelos valores:

  Calculando o tamanho de um arquivo

  Para calcular o tamanho de um arquivo em C, devemos posicionar o cursor de arquivo no final dele e calcular sua posição através da função ftell().
  O programa a seguir calcula o tamanho em bytes de um arquivo chamado "arquivo.txt".
#include <stdio.h>

main()
{
  FILE *fp;
  int tamanho;

  fp = fopen("arquivo.txt","rb");
  fseek(fp, 0, 2);
  tamanho = ftell(fp);

  printf("Tamanho do arquivo: %d\n", tamanho);

  fclose(fp);
}
  O valor 2 na função fseek() é a constante SEEK_END.


  Trabalhe com os dados de arquivos sempre na memória do micro

  Um arquivo de disco é o armazenamento permanente de dados, que são transferidos a partir de uma memória volátil (RAM). Isto é feito para que os dados não sejam perdidos quando o micro é desligado.
  Trabalhamos sempre com os dados na memória RAM do micro, pois é o tipo de memória mais rápido e de uso eficiente do sistema. Dessa forma, quando necessitamos utilizar esses dados, devemos sempre copiá-los do disco de volta para a memória RAM. Se os dados couberem por completo na memória, carregue-os todos de uma vez em um vetor. Caso o arquivo seja muito grande, carregue uma parte do arquivo por vez em um vetor, com um tamanho que caiba na memória.
  Nunca crie sistemas onde o acesso aos dados de arquivo seja feito byte a byte, com uso abusivo da função fseek().

  No exemplo a seguir, iremos carregar um arquivo binário de MSX, modificar seu cabeçalho e salvar com o nome de "arqmod.bin". O arquivo deverá ser menor ou igual a 1024 bytes.
#include <stdio.h>

unsigned char buffer[1024];

main(int argv, char * argc[])
{
  FILE *fp;
  int tamanho;

  if (argv!=2)
  {
    printf("Erro. Nome de arquivo nao informado.\n");
    return;
  }

  // Arbre arquivo para leitura
  fp = fopen(argc[1],"rb");
  if (fp == 0)
  {
    printf("Erro. arquivo %s nao encontrado.\n", argc[1]);
    return;
  }  

  // Calcula o tamanho
  fseek(fp, 0, 2);
  tamanho = ftell(fp);

  if (tamanho > 1024)
  {
    printf("Arquivo muito grande. Maximo 1024 bytes.\n");
    return;
  }

  // Tranfere arquivo para memoria
  fseek(fp, 0, 0); // Volta inicio
  fread(&buffer, tamanho, 1, fp);

  // Fecha arquivo aberto para leitura
  fclose(fp);

  // Altera header (endereco de execucao)
  buffer[5] = 0x00; buffer[6] = 0xCD;

  // Salva um novo arquivo - nome: arqmod.bin
  fp = fopen("arqmod.bin","wb");
  fwrite(&buffer, tamanho, 1, fp);
  fclose(fp);
}
  Execute o programa colocando como parâmetro o nome do arquivo. Por exemplo, se o nome do programa for "MODIFICA.COM" e do arquivo binário "FILE.BIN", digite no MSX-DOS:
A> modifica file.bin

  Nota importante: observe o comando "fseek(fp, 0, 0);" antes da leitura dos dados. Como havíamos movido o cursor para o fim do arquivo para calcular seu tamanho, temos que tomar o cuidado de retornar o ponteiro ao incio do arquivo, sob pena de não carregarmos os dados desse arquivo.


  Gravando e Recuperando Estruturas

  O programa a seguir cria uma ficha de alunos e a salva no formato binário.
#include <stdio.h>
#include <string.h>

struct mod_ficha
{
  char nome[10];
  int idade;
  int serie;
  float cr;

} ficha;

FILE *fp;

void main(void)
{
  // Preenche ficha
  strcpy(ficha.nome, "Catarina");
  ficha.idade = 12;
  ficha.serie = 6;
  ficha.cr = 8.9;

  fp = fopen("ficha.fch","wb");
  fwrite(&ficha, sizeof(struct mod_ficha), 1, fp);
  fclose(fp);
}

  Resultado, editando o arquivo "ficha.fch" em um editor hexadecimal.
 Bytes                               | ASCII
 ------------------------------------+-------------
 43 61 74 61 72 69 6E 61 00 00 00 00 | Catarina....
 0C 00 00 00 06 00 00 00 66 66 0E 41 | ........ff.A

  Recuperando o arquivo:
#include <stdio.h>
#include <string.h>

struct mod_ficha
{
  char nome[10];
  int idade;
  int serie;
  float cr;

} ficha;

FILE *fp;

void main(void)
{
  fp = fopen("ficha.fch","rb");
  fread(&ficha, sizeof(struct mod_ficha), 1, fp);
  fclose(fp);

  printf("Nome: %s\n", ficha.nome);
  printf("Idade: %d\n", ficha.idade);
  printf("Série: %d\n", ficha.serie);
  printf("Coeficiente de rendimento: %.2f\n", ficha.cr);
}
  Saída:
  Nome: Catarina
  Idade: 12
  Série: 6
  Coeficiente de rendimento: 8.90


<< Anterior Linguagem C Próxima >>