Mudanças entre as edições de "AULA 22 - Programação 1 - Engenharia"

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
Linha 585: Linha 585:
 
*Exercício: Substitua o modo de append por uma simples escrita (w). Reexecute o programa conforme especificado anteriormente.
 
*Exercício: Substitua o modo de append por uma simples escrita (w). Reexecute o programa conforme especificado anteriormente.
  
==Exemplo de gravação de uma tabela com estruturas contendo ponteiros==
 
  
Observe no exemplo abaixo que um vetor de estruturas (tabela) contendo ponteiros pode ter problemas no seu salvamento, caso as áreas apontadas não sejam gravadas.
 
A tabela tab_registros2 se for gravada com salvar_em_arq2() perderá dados pois os dados apontados por nome não serão salvos com fwrite.
 
Pode-se contornar este problema gravando cada estrutura em uma linha de forma formatada, separada por delimitadores.  Ver função salvar_am_arq2_vOK().
 
A recuperação dos dados deve prever a reconstituição da tabela (ver restaurar_tab_do_arq2()).
 
 
Note o significado das formatações usadas no scanf/fscanf: [https://en.wikipedia.org/wiki/Scanf_format_string]
 
*qualquer caracter em branco na string de formato faz com que a função ignore quaisquer espaço em branco, newline, tab ou qualquer agrupamento destes, ATÉ que seja encontrado um caracter diferente destes.
 
*em condições normais o fscanf retorna as entradas scaneadas. No exemplo abaixo, em condições normais ela retorna 2;
 
*no final do arquivo ela retorna o caracter EOF, usado no exemplo para terminar o loop de leitura.
 
 
<syntaxhighlight lang=c>
 
#include <stdio.h>
 
#include <string.h>
 
#include <stdlib.h>
 
 
#define TAM_TAB2 3
 
 
 
struct tipo_registro2{
 
  char *nome;
 
  int idade;
 
} tab_registros2[TAM_TAB2] = {
 
      {"alfa", 10},
 
      {"beta", 30},
 
      {"epson", 20},
 
  };
 
 
void salvar_em_arq2()
 
{
 
  /* PROBLEMAS... - a estrutura tem ponteiros... */
 
  FILE *ptr;
 
  ptr =fopen("teste2.dat", "w+");
 
  fwrite(tab_registros2, sizeof(struct tipo_registro2),TAM_TAB2,ptr);
 
  fclose(ptr);
 
}
 
 
void salvar_am_arq2_vOK()
 
{
 
  FILE *ptr;
 
  int i;
 
 
  ptr =fopen("teste2.dat", "w+");
 
  for (i=0;i<TAM_TAB2;i++)
 
    fprintf (ptr, "%s:%d\n", tab_registros2[i].nome, tab_registros2[i].idade);
 
  fclose(ptr);
 
}
 
 
 
void print_tab2()
 
{
 
  int i;
 
 
  for (i=0;i<TAM_TAB2;i++) {
 
    printf ("%s:%d\n", tab_registros2[i].nome, tab_registros2[i].idade);
 
  }
 
}
 
 
void restaurar_tab_do_arq2()
 
{
 
  char buffer[100+1];
 
  FILE *ptr;
 
  int ret,i=0;
 
 
  ptr =fopen("teste2.dat", "r");
 
  while  (ret!=EOF) {
 
    ret=fscanf (ptr, " %[^:]:%d", buffer,&tab_registros2[i].idade);
 
    if (ret==2) {
 
        tab_registros2[i].nome=(char *)malloc(strlen(buffer));
 
        strcpy(tab_registros2[i].nome, buffer);
 
        printf("i=%d ret=%d %s %d\n",i,ret,tab_registros2[i].nome, tab_registros2[i].idade);
 
    } else if (ret!=EOF)
 
        printf("Provavelmente existe um erro no arrquivo de dados\n");
 
    i++;
 
  }
 
fclose(ptr);
 
}
 
 
main()
 
{
 
  salvar_am_arq2_vOK();
 
  restaurar_tab_do_arq2();
 
  print_tab2();
 
  /* a fazer = liberar areas alocadas dinamicamente */
 
}
 
</syntaxhighlight>
 
  
 
===Exemplo de gravação/leitura de uma tabela de estruturas na forma binária usando fwrite e fread===
 
===Exemplo de gravação/leitura de uma tabela de estruturas na forma binária usando fwrite e fread===

Edição das 07h23min de 23 de abril de 2021

Objetivos

Após esta aula o aluno terá:

  • Noções básicas do sistema de arquivos no Linux
  • Capacidade de desenvolver aplicações simples em C e que fazem acesso a arquivos com funções de alto nível da biblioteca.

O sistema de arquivos no Linux

O Arquivo

Um arquivo é um conjunto de dados que pode ser referenciado por um nome e pode ter outros atributos tais como: permissão para leitura e escrita, data da criação, data da última modificação etc.

Note que um arquivo pode conter dados (um relatório, por exemplo), um programa C, um programa executável, música, fotos etc. Seja qual for a natureza dos dados o armazenamento será na forma de bits.

Normalmente, arquivos são armazenados em memórias secundárias, tais como CD, hard disk etc, mas eles podem se armazenados na memória principal também (RAM, FLASH).

Quanto a forma como os dados são armazenados, podemos dizer que os arquivos são binários ou texto. Qualquer um deles armazena bits mas os bytes de um arquivo texto devem ser interpretados como códigos ASCII e são organizados em linhas.

Se abrir um arquivo texto com o "vi" pode-se "ver" os bytes armazenados no arquivo:
 	
vi /etc/passwd
Entrar em modo comando (SHIFT :) e fazer:
:%!xxd

Ao abrir um arquivo a partir de um programa em C, pode-se ter comportamentos diferentes se optar por abrir em modo texto ou binário

Sistema de Arquivos

Um sistema tal como o Linux possui milhares de arquivos. Para que arquivos possam ser acessados e armazenados de forma consistente, eles são organizados em um sistema de arquivos.

Tipicamente, um sistema de arquivos ocupa uma área de um disco (ou mídia de armazenamento). Nesta área ficam armazenados blocos de armazenamento dos dados dos arquivos e também as estruturas chamadas de inodes.

Um inode é um estrutura que possui as propriedades do arquivo e ponteiros para os blocos que contém os dados do arquivo. Tipicamente um sistema de arquivos possui uma lista de inodes que permite "indexar" cada um dos arquivos do sistema de arquivos.

Existem vários formatos de sistema de arquivos, dependendo do sistema operacional. No linux os formatos mais conhecidos são: ext2, ext3, ext4 etc.

Um sistema de arquivos normalmente possui uma estrutura de dados inicial chamada de superbloco. O superbloco traz informações sobre o tamanho de blocos do sistema, o início da lista de inodes (/), etc.

+-------------+-----------------+------------------------+
| superbloco  | lista de inodes | blocos dos arquivos    |
+-------------+-----------------+------------------------+

Diretórios

São arquivos especiais que contém basicamente uma lista contendo nome e inode correspondente dos arquivos que o diretório contém.

Em um sistema de arquivos, o diretório / é o diretório raiz do sistema, a partir do qual pode-se encontrar todos os demais arquivos.

Referência a um arquivo

A localização de um arquivo pode ser realizada pela referência absoluta, ou seja, desde o diretório / do sistema:

cat /etc/passwd

O comando cat tem por objetivo mostrar no terminal o conteúdo do arquivo passwd. Para que este arquivo seja encontrado na árvore de diretórios, deve-se fornecer a referência absoluta, desde o diretório /

Uma alternativa de acesso, é o uso da referência relativa ao diretório de trabalho. O conceito de diretório de trabalho é criado pelo interpretador de comandos (shell). Desta forma pode-se por exemplo fazer o comando:

cat passwd

O sistema procurará o arquivo passwd dentro do diretório de trabalho, que é referenciado armazenado pelo shell. Neste caso, o diretório de trabalho deveria ser /etc

cd /etc
cat passwd
No Linux/Unix tudo é arquivo

No Linux, qualquer referência/acesso ao hardware/dispositivos é realizada na forma de acesso a arquivo. Ver arquivos no diretório de dispositivos:

 ls -l /dev

Como consequência, a partir de um programa em C, é possível abrir e escrever/ler em um dispositivo (desde que se tenha autorização).

Acessando arquivos a partir de programas C

Acesso a arquivos: funções de baixo e alto nível

Em sistemas do porte do Linux e Windows, por questões de segurança e controle, todo acesso a arquivo é realizado através de código do sistema operacional. Desta forma, um programa que deseja acessar um arquivo deve gerar uma CHAMADA AO SISTEMA. O Linux (assim como outros sistemas) possui uma API (Application Programming Interface) bem definida, na forma de um conjunto de chamadas que permitem realizar uma série de funcionalidades (serviços) para os processos (programas em execução).

Um programa em C realiza uma CHAMADA AO SISTEMA com auxílio de funções da biblioteca C (a glib no caso do Linux). Duas categorias de funções para acesso a arquivo são disponibilizadas (ver detalhes aqui):

  • Funções de baixo nível: acessam diretamente o sistema;
  • Funções de alto nível: as funções intermediam o acesso, criando buffers no espaço de endereçamento do processo. As funções de baixo nível são invocadas para ler e escrever dados no buffer.

Acesso a arquivo em MODO TEXTO através de funções de alto nível

O acesso em alto nível é realizado usando uma estrutura do tipo FILE definida no stdio.h. Todo acesso passa inicialmente por abrir o arquivo (função fopen), ler/escrever (várias funções, tipo fread(), fwrite()) e fechar o arquivo (fclose()). As principais funções são mostradas na tabela abaixo.

função Descrição Comentário
fopen abrir arquivo retorna um ponteiro para FILE dado o nome do arquivo
fclose fechar arquivo descrito por FILE
fprintf escrever no arquivo de forma formatada
fscanf ler de um arquivo de forma formatada A função retorna o "define" (um inteiro) EOF (end-of-file) quando não existe mais dados a serem lidos.
fputc escrever um caracter do arquivo
fgetc ler um caracter do arquivo
fputs escrever string no arquivo
fgets ler string no arquivo
fwrite escrever dados de forma não formatada
fread ler dados de forma não formada

Escrevendo e lendo um arquivo texto de forma formatada

Nos exemplos que se seguem, serão usadas as funções fopen e fclose, para abrir e fechar arquivo e fprintf() e fscanf() para leitura e escrita. A forma é similar ao printf e scanf, a não ser pelo fato de que a escrita e leitura é realizada no arquivo indicado por p_arq

  Observar que um arquivo que está sendo acessado possui uma posição corrente de acesso de forma que uma nova leitura ou escrita sempre avança para "frente" nos dados do arquivo. 

Escrevendo de forma formatada com fprintf

#include <stdio.h>
#include <stdlib.h>

/*escrevendo no arquivo IFSC.txt*/
int main()
{
  FILE *p_arq;
  int i;
  int res;

  if ((p_arq=fopen("IFSC.txt", "w")) == NULL) {
     printf("Problemas na abertura do arquivo\n");
     exit(EXIT_FAILURE);
  }

  for (i = 0; i<10;i++) {
  /* A funcao fprintf devolve o número de bytes gravados  ou EOF se houve erro na gravação */
      if((res = fprintf(p_arq,"Linha %d\n",i))==EOF) {  					  	    
          printf("Erro\n");
          break;
      }
  }
  fclose(p_arq);
  return EXIT_SUCCESS;
}
Note que se o arquivo IFSC.txt não existir, ele será criado.

Para ver o que foi escrito no arquivo faça:

cat IFSC.txt

Use o vi para ver os bytes armazenados no arquivo IFSC.TXT.

Lendo de forma formata com fscanf

Para ler o arquivo IFSC.txt pode-se usar o fscanf().

#include <stdio.h>
#include <stdlib.h>

/*lendo do arquivo IFSC.txt*/
int main()
{
  FILE *p_arq;
  int i,j;
  int res;
  char buff[100];

  if ((p_arq=fopen("IFSC.txt", "r")) == NULL) {
     printf("Problemas na abertura do arquivo\n");
     exit(EXIT_FAILURE);
  }

  for (i = 0; i<10;i++) {
      if((res = fscanf(p_arq,"%s %d",buff,&j))==EOF) {  					  	    
         printf("Fim de leitura\n");
         break;
      }
      printf("%s %d\n",buff,j);
  }
  fclose(p_arq);
  return EXIT_SUCCESS;
}

Note que o fscanf se comporta de forma similar ao scanf. A função retorna o define EOF (end-of-file) quando não existe mais dados a serem lidos.

Exemplo 1: lendo conteúdo com fscanf
#include<stdio.h>

int main (void){

  int dia, mes, ano;
  FILE *arq;

  arq = fopen("a.txt", "r");
  if (arq != NULL)
    printf("Arquivo aberto com sucesso, continuando...\n");
  else
    printf("Não foi possível abrir o arquivo\n");

  fscanf(arq, "%d/%d/%d", &dia, &mes, &ano);

  printf("O dia eh: %d/%d/%d\n", dia, mes, ano);

  fclose(arq);
}
Exemplo 2: escrevendo e lendo conteúdo em arquivos
#include <stdio.h>
#include <stdlib.h>

int main (void){

  FILE *pont_arq; // cria variável ponteiro para o arquivo
  char palavra[20]; // variável do tipo string

  //abrindo o arquivo com tipo de abertura w
  pont_arq = fopen("arquivo_palavra.txt", "w"); //modo padrão de abertura do arquivo é texto (adicionar b se quiser binário - Ex "rb", "wb", etc)

  //testando se o arquivo foi realmente criado
  if (pont_arq != NULL)
    printf("Arquivo aberto com sucesso, continuando...\n");
  else
    printf("Não foi possível abrir o arquivo\n");

  printf("Escreva uma palavra para testar gravacao de arquivo: ");
  scanf("%[^\n]s", palavra); // [^\n] ler espaço como caracter válido

  //escreve no arquivo texto:"2/5/2006"
  fprintf(pont_arq, "%d/%d/%d\n", 2, 5, 2006);

  //usando fprintf para armazenar a string no arquivo
  fprintf(pont_arq, "%s\n", palavra);

  //usando fclose para fechar o arquivo
  fclose(pont_arq);

  printf("Dados gravados com sucesso\n!");

  return(0);
}
Exemplo 3: escrevendo e lendo conteúdo em arquivos
#include <stdio.h>
#include <stdlib.h>

/*escrevendo no arquivo IFSC.txt*/
int main(void)
{
  FILE *p_arq;
  int i;
  int res;

  if ((p_arq=fopen("IFSC.txt", "w")) == NULL) {
     printf("Problemas na abertura do arquivo\n");
     exit(EXIT_FAILURE);
  }

  for (i = 0; i<10;i++) {
  /* A funcao fprintf devolve o número de bytes gravados  ou EOF se houve erro na gravação */
      if((res = fprintf(p_arq,"Linha %d\n",i)) == EOF) {
	  printf("Erro\n");
	  break;
      }
  }
  fclose(p_arq);
  return EXIT_SUCCESS;
}

Exercício 1

Implementar um programa que soma duas matrizes fornecidas em dois arquivos texto separados: MatA.dat e MatB.dat. Colocar o resultado em um arquivo chamado MatC.dat.

solução Ex. 1
#include <stdio.h>
#include <stdlib.h>

void main(void){

  FILE *p_arq;
  int i,j,res;
  float MatA[5][5], MatB[5][5], MatR[5][5];

  /* Ler a matriz MatA do arquivo */
  if ((p_arq=fopen("MatA.dat", "r")) == NULL) {
     printf("Problemas na abertura do arquivo\n");
     return;
  }

  for (i =0;i<5;i++) {
      for (j=0;j<5;j++) {
      	if((res = fscanf(p_arq,"%f",&MatA[i][j]))==EOF){
	         printf("Fim de leitura\n");
			 break;
      	}
      	printf("%f ",MatA[i][j]);
      }
      printf("\n");
  }
  fclose(p_arq);

  /* Ler a matriz MatB do arquivo */

  printf("\n\n");

  /* Ler a matriz MatB do arquivo */
  if ((p_arq=fopen("MatB.dat", "r")) == NULL) {
     printf("Problemas na abertura do arquivo\n");
       exit(EXIT_FAILURE);
  }

  for (i =0;i<5;i++) {
      for (j=0;j<5;j++) {
      	if((res = fscanf(p_arq,"%f",&MatB[i][j]))==EOF){
	         printf("Fim de leitura\n");
			 break;
      	}
      	printf("%f ",MatB[i][j]);
      }
      printf("\n");
  }
  fclose(p_arq);

  /* Calcular a soma das matrizes e colocar resultado em MatR */

  for (i =0;i<5;i++) {
      for (j=0;j<5;j++) {
      	MatR[i][j]=MatA[i][j]+MatB[i][j];
      }
  }
  printf("Resultado da Adição\n");
  for (i =0;i<5;i++) {
      for (j=0;j<5;j++) {
          printf("%f ", MatR[i][j]);
      }
      printf("\n");
  }
  /* Armazenar MatR em arquivo */

  if ((p_arq=fopen("MatR.dat", "w")) == NULL) {
     printf("Problemas na abertura do arquivo\n");
     return;
  }

  for (i =0;i<5;i++) {
      for (j=0;j<5;j++) {
         if((res = fprintf(p_arq,"%f ",MatR[i][j]))==EOF) {
	         printf("erro\n");
			 break;
      	 }
      }
      fprintf(p_arq,"\n");
  }
  fclose(p_arq);
}

Exemplo de gravação na forma texto de uma tabela com estruturas

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define TAM_TAB2 3


struct tipo_registro2{
   char nome[30];
   int idade;
   float nota_final;
} tab_registros[TAM_TAB2] = {
      {"alfa da silva", 10, 9.5},
      {"beta da silva", 30, 6.9},
      {"epson da silva", 20, 7.5},
   };

/*
  Esta função mostra como salvar a tabela de estruturas na forma de um arquivo texto contendo uma estrutura por lionha. Os campos são separados com :
*/

void salvar_am_arq()
{
  FILE *ptr;
  int i;

  if ((ptr = fopen("teste.dat", "w+"))== NULL) {
     printf("Erro na abertura de arquivo\n");
     exit(-1);
  }
  for (i=0;i<TAM_TAB2;i++)
     fprintf (ptr, "%s:%d:%f\n", tab_registros[i].nome, tab_registros[i].idade, tab_registros[i].nota_final);
  fclose(ptr);
}

/*
  Esta função mostra como recuperar a tabela de estruturas na forma de um arquivo texto contendo uma estrutura por linha. Os campos são separados com :
*/
void restaurar_tab_do_arq()
{
  char buffer[100+1];
  FILE *ptr;
  int ret=0,i=0;

  if ((ptr = fopen("teste.dat", "r"))== NULL) {
     printf("Erro na abertura de arquivo\n");
     exit(-1);
  }
  while  (ret != EOF) {
     ret = fscanf (ptr, " %[^:]:%d:%f", tab_registros[i].nome, &tab_registros[i].idade, &tab_registros[i].nota_final);
     if (ret==3) { /* ret contém o número de itens lidos */
         printf("REGISTRO %d %s %d %f\n",i,tab_registros[i].nome, tab_registros[i].idade, tab_registros[i].nota_final);
    } else if (ret!=EOF)
         printf("Provavelmente existe um erro no arrquivo de dados\n");
    i++;
  }
 fclose(ptr);
}

int main(void){
  salvar_am_arq();
  restaurar_tab_do_arq();
  return 0;

}

Escrevendo e Lendo usando fgets e fputs

Exercício 1

Neste exemplo usaremos as funções fgetc e fputc para ler e escrever caracteres ASCII nos arquivos. Seja um programa que conta o número de ocorrências do caracter 'a', remova esses caracteres 'a' e salve os caracteres em um novo arquivo destino:

solução Ex. 2
#include <stdio.h>
#include <stdlib.h>
main()
{
   FILE *fp_fonte,*fp_destino;
   int x,cont=0;
                   
   if((fp_fonte=fopen("teste.dat","r")) == NULL) {
		puts("Não conseguiu abrir o arquivo\n");
		exit(1);
   }
   if((fp_destino=fopen("dest.dat","w")) == NULL){
		puts("Não conseguiu abrir o arquivo\n");
		exit(1);
   }

   /* note que fgetc retorna um inteiro contendo o ASCII lido */
   while ((x=fgetc(fp_fonte)) != EOF){
      if(x=='a')
         cont++;
      else
	 if((x=fputc(x,fp_destino))==EOF) {
		puts("Não conseguiu escrever no arquivo\n");
		exit(1);
	 }	
   }	
   printf("ocorrências de a = %d\n", cont);
   fclose(fp_fonte);
   fclose(fp_destino);
}
Note que fputc recebe o caracter como um inteiro mas realiza um cast para
unsigned char com fins de escrevê-lo no arquivo.


Exemplo 4: escrevendo e lendo string em arquivos
#include <stdio.h>
#include <stdlib.h>

int main (void){

  FILE *pont_arq;
  char texto_str[20];

  //abrindo o arquivo_frase em modo "somente leitura"
  pont_arq = fopen("arquivo_palavra.txt", "r");

  //enquanto não for fim de arquivo o looping será executado
  //e será impresso o texto
  while(fgets(texto_str, 20, pont_arq) != NULL)
    printf("%s", texto_str);

  //fechando o arquivo
  fclose(pont_arq);

  return(0);
}

Exemplo 3

Neste exemplo vamos explorar o modo de abertura do arquivo para fazer um append (escrever no final do arquivo). Ver time() e ctime() em http://www.cplusplus.com/reference/ctime/.

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
 
int main(void)
{
   time_t ltime;
   FILE *fp;
   int num;

   /* ler a hora/data do sistema e armazenar em ltime */
   time(&ltime); 

   if ((fp=fopen("DATA.txt", "a")) == NULL) {
       printf("Problemas na abertura do arquivo\n");
       exit(EXIT_FAILURE);
   }
   /* escrever hora/data lida em arquivo, mas converter antes para string (ctime) */
   if ((num = fputs( ctime(&ltime), fp )) != EOF ) {
       fclose(fp);
   } else {
       printf("Erro na escrita do arquivo!\n");
   }
   return (EXIT_SUCCESS);
}

Execute o programa da forma (suponha que se chame LOG_tempo:

 log_tempo
 cat DATA.txt
 log_tempo
 cat DATA.txt
 log_tempo
 cat DATA.txt  
 
  • Exercício: Substitua o modo de append por uma simples escrita (w). Reexecute o programa conforme especificado anteriormente.


Exemplo de gravação/leitura de uma tabela de estruturas na forma binária usando fwrite e fread

#include <stdio.h>
#include <string.h> 
#include <stdlib.h>
 
#define TAM_TAB2 3
 
 
struct tipo_registro2{
   char nome[30];
   int idade;
   float nota_final;
} tab_registros[TAM_TAB2] = {
      {"alfa da silva", 10, 9.5},
      {"beta da silva", 30, 6.9}, 
      {"epson da silva", 20, 7.5},
   };

  struct tipo_registro2 aux[TAM_TAB2];
/*
  Esta função mostra como salvar a tabela de estruturas na forma de um arquivo texto contendo uma estrutura por lionha. Os campos são separados com :
*/

void salvar_am_arq()
{
  FILE *ptr;
  int i;
 
  if ((ptr = fopen("teste.dat", "w+"))== NULL) {
     printf("Erro na abertura de arquivo\n");
     exit(-1);
  }
  fwrite (tab_registros, sizeof(struct tipo_registro2),TAM_TAB2,ptr);
  fclose(ptr);
}

/*
  Esta função mostra como recuperar a tabela de estruturas na forma de um arquivo texto contendo uma estrutura por linha. Os campos são separados com :
*/
void restaurar_tab_do_arq()
{
  char buffer[100+1];
  FILE *ptr;
  int ret;
 
  if ((ptr = fopen("teste.dat", "r"))== NULL) {
     printf("Erro na abertura de arquivo\n");
     exit(-1);
  }
  ret = fread(aux,sizeof(struct tipo_registro2),TAM_TAB2,ptr);
  printf("número de itens lidos = %d\n", ret);
  fclose(ptr);
}
 
main()
{
  salvar_am_arq();
  restaurar_tab_do_arq();
  printf("%s\n", aux[2].nome);
}


Ainda funções de acesso a arquivos - posicionando cursor sobre o arquivo

A localização corrente do acesso a um arquivo pode ser modificada antes de uma leitura ou escrita. Tipicamente, quando se abre uma arquivo para leitura/escrita, o "cursor" de acesso é 0, ou seja início do arquivo. Se o arquivo for aberto em modo append, o "cursor" é posicionado no final. A cada acesso (leitura ou esrita), este cursor é incrementado conforme o número de dados lidos ou escritos.

É possível entretanto modificar a posição deste cursor, tipicamente com as funções fseek() e rewind(). (ver [1]).

Considere o programa abaixo que escreve um vetor de 100 inteiros em um arquivo.

#include <stdio.h>

int x[100];

void main()
{
  FILE *fp;

  fp = fopen("teste.dat","w");
  x[0]=32;
  x[90]=11;
  fwrite(x, sizeof(int),100,fp);
  fclose(fp);
}

Note que o vetor, sendo uma variável global não inicialiazada, será zerado pelo procedimento de startup do programa. Entretanto, a posição 90 recebe um valor (11).

Agora observe o programa seguinte que lê especificamente a posição 90 e na sequência restabelece o cursor no início. Note que o fread lê somente um inteiro na posição corrente do arquivo. A posição corrente foi determinada por fseek e depois retornada para o início com rewind.

#include <stdio.h>

int y;

void main()
{
  FILE *fp;

  fp = fopen("teste.dat","r");
  fseek(fp, 90*sizeof(int), SEEK_SET);
  fread(&y, sizeof(int),1,fp);
  printf("y=%d\n", y);
  rewind(fp);
  fread(&y, sizeof(int),1,fp);
  printf("y=%d\n", y);
  fclose(fp);
}

Exercício

Escreva um programa que receba do usuário 5 números inteiros e o nome do arquivo no qual eles devem ser armazenados. Em seguida, ler do arquivo estes valores armazenados copiando-os para um vetor de inteiros e imprimindo na tela.

solução Ex. 1
#include <stdio.h>

int main(){

FILE *arq;
int i, temp, vet[5];
char nome_arq[20];

printf("Informe o nome do arquivo: ");
scanf("%[^\n]s",nome_arq);

if ((arq = fopen (nome_arq, "w+"))== NULL){
  printf("Erro ao abrir o arquivo %s", nome_arq);
  return (1);
}

for (i=0; i<5 ; i++){
  printf("informe um valor inteiro: ");
  scanf("%d", &temp);
  fprintf(arq, "%d", temp);
  if (i < 4)
    fprintf(arq, "\n");
}
rewind(arq);  //Retorna o indicador de posição do ponteiro FILE em relação ao arquivo para o seu início.

i = 0;
while ( !feof(arq) ){     //Retorna zero se o final do arquivo foi atingido e um valor não nulo caso contrário.
  fscanf (arq, "%d", &vet[i]);
  printf("%d\n",vet[i]);
  i++;
}
fclose(arq);
return 0;
}