Mudanças entre as edições de "SOP-arquivos"

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
Linha 245: Linha 245:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Pode-se ver que, assim como existe ''fprintf'', há a função ''fscanf'', que funciona da mesma maneira que ''scanf''. O programa desse exemplo funciona para qualquer arquivo que contenha números. Pode haver mais de um número por linha, contanto que estejam separados por espaços (não pode haver nada diferente de números e espaços). Finalmente, pode existir qualquer quantidade de linhas (experimente executar o programa !).
+
Pode-se ver que assim como existe ''fprintf'', há a função ''fscanf'', que funciona da mesma maneira que ''scanf''. O programa desse exemplo funciona para qualquer arquivo que contenha números. Pode haver mais de um número por linha, contanto que estejam separados por espaços (não pode haver nada diferente de números e espaços). Finalmente, pode existir qualquer quantidade de linhas (experimente executar o programa !).
 +
 
 +
== Lendo e escrevendo valores ''struct'' ==
 +
 
 +
<syntaxhighlight lang=c>
 +
#include<stdio.h>
 +
 
 +
struct Pessoa {
 +
  char nome[1024];
 +
  int idade;
 +
  char cpf[12];
 +
};
 +
 
 +
int main() {
 +
  char path[256];
 +
  FILE * arquivo;
 +
  char opcao;
 +
  struct Pessoa umaPessoa;
 +
 
 +
  printf("Digite o nome de um arquivo: ");
 +
  scanf("%s", path);
 +
 
 +
  printf("\nVou gravar registros de pessoas nesse arquivo\n");
 +
 
 +
  arquivo = fopen(path, "w");
 +
  if (arquivo == NULL) {
 +
    perror("Ops ... erro ao acessar esse arquivo: ");
 +
    return 1;
 +
  }
 +
 
 +
  do {
 +
    printf("Nome: ");
 +
    scanf(" %[^\n]", umaPessoa.nome);
 +
    printf("CPF (sem pontos ou traços): ");
 +
    scanf("%s", umaPessoa.cpf);
 +
    printf("Idade: ");
 +
    scanf("%d", &umaPessoa.idade);
 +
 
 +
    fprintf(arquivo, "%s:%s:%d\n", umaPessoa.nome, umaPessoa.cpf, umaPessoa.idade);
 +
 
 +
    printf("Continuar (S/N) ?: ");
 +
    scanf(" %c", &opcao);
 +
  } while ((opcao == 'S') || (opcao == 's'));
 +
 
 +
  fclose(arquivo);
 +
 
 +
}
 +
</syntaxhighlight>

Edição das 20h24min de 15 de novembro de 2009

Arquivos na linguagem C

Para um programador, arquivos são repositórios permanentes de dados, os quais usualmente ficam em midia não volátil (disco rígido, CD ou DVD, pendrive, e outros). Arquivos servem para guardar informações que devem continuar a existir mesmo que termine o processo que as criou. Um exemplo é a agenda, cujo conteúdo deve ser preservado para futuras consultas e modificações. Mas além de serem depósitos de dados, arquivos possuem características bem definidas do ponto de vista de programação.

Um arquivo é uma sequência de bytes, que pode ser acessada, lida e modificada por meio de funções específicas existentes na biblioteca padrão da linguagem C. Essas funções servem para abrir e fechar um arquivo, ler e escrever uma certa quantidade de bytes, e mudar a posição da próxima leitura ou escrita.

Escrevendo em um arquivo

Abaixo segue um exemplo de um programa para escrever uma linha em um arquivo:

#include<stdio.h>

int main() {
  char linha[256];
  FILE * arquivo;

  printf("Digite uma linha: ");
  scanf("%[^\n]", linha);
  
  printf("Vou gravar isto no arquivo teste.txt\n");
  arquivo = fopen("teste.txt", "w");
  if (arquivo == NULL) {
    perror("Nao conseguiu abrir o arquivo");
    return 1;
  }
  fprintf(arquivo, "%s\n", linha);
  fclose(arquivo);

  printf("Pronto ... veja o arquivo teste.txt !\n");
}

Esse pequeno programa evidencia que trabalhar com arquivos é muito parecido a trabalhar com escrita na tela e leitura do teclado. Mas primeiro deve-se focar nas linhas do programa que têm relação direta com arquivos. Para começar, um arquivo é referenciado por uma variável do tipo FILE *:

  FILE * arquivo;

Em seguida, o arquivo a ser lido ou escrito deve ser aberto, usando-se a função FILE * fopen(char * nome_arquivo, char * modo):

  arquivo = fopen("teste.txt", "w");

Como se pode ver, a função fopen precisa de dois parâmetros do tipo char * (quer dizer, dois parâmetros string). O primeiro é o caminho do arquivo a ser aberto, e o segundo é o modo de abertura (o que se pretende fazer com ele: ler, escrever, adicionar dados ao final, ler e escrever). No exemplo acima, vai-se abrir o arquivo teste.txt para escrita (modo "w", de write). O valor de retorno de fopen é do tipo FILE *, e corresponde a uma descrição do arquivo que foi aberto. Caso aconteça algum erro (ex: não há permissão para criar o arquivo), fopen retorna o valor NULL. O exemplo testa se isto acontece da seguinte forma:

  if (arquivo == NULL) {
    perror("Nao conseguiu abrir o arquivo");
    return 1;
  }

Uma vez o arquivo estando aberto para escrita, pode-se escrever nele usando-se a função fprintf. Essa função é idêntica à função printf que se usa para escrever na tela. Porém fprintf precisa de um parâmetro adicional, deve ser a variável que corresponde ao arquivo aberto (primeiro parâmetro da função):

  fprintf(arquivo, "%s\n", linha);

Finalmente, quando não se quer mais escrever no arquivo deve-se chamar a função fclose para fechá-lo:

  fclose(arquivo);

Lendo uma linha de um arquivo

A leitura de um arquivo é parecida, com algumas pequenas modificações em sua abertura (deve-se indicar que o mode de operação será "r", de "read"), e usando-se a função fscanf para ler dados do arquivo. O exemplo abaixo mostra um programa para ler a primeira linha de um arquivo:

#include<stdio.h>

int main() {
  char linha[1024];
  char nome[256];
  FILE * arquivo;

  printf("Digite o nome de um arquivo: ");
  scanf("%s", nome);
  
  printf("Vou mostrar a primeira linha do arquivo %s\n", nome);

  arquivo = fopen(nome, "r");
  if (arquivo == NULL) {
    perror("Ops ... erro ao acessar esse arquivo: ");
    return 1;
  }

  fgets(linha, 1024, arquivo);
  fclose(arquivo);

  printf("Eis a primeira linha do arquivo: \n\n%s\n\n", linha);

}

Como adiantado, na abertura com fopen deve-se usar o valor "r" para o modo:

  arquivo = fopen(nome, "r");

Já a leitura de uma linha pode ser feita mais facilmente com a função fgets:

  fgets(linha, 1024, arquivo);

A função char * fgets(char * resultado, int max_caracteres, FILE * arquivo) lê uma linha de um arquivo com até max_caracteres e a guarda na variável passada no parâmetro resultado. No exemplo acima, fgets lê uma linha com até 1024 caracteres e a guarda na variável linha.

Lendo todas as linhas de um arquivo

Nesse próximo exemplo, abre-se um arquivo para leitura e lêem-se todas suas linhas, mostrando-as na tela:

#include<stdio.h>

int main() {
  char linha[1024];
  char nome[256];
  char * ok;
  FILE * arquivo;

  printf("Digite o nome de um arquivo: ");
  scanf("%s", nome);
  
  printf("\nVou mostrar todas as linhas do arquivo %s\n\n", nome);

  arquivo = fopen(nome, "r");
  if (arquivo == NULL) {
    perror("Ops ... erro ao acessar esse arquivo: ");
    return 1;
  }

  do {
    ok = fgets(linha, 1024, arquivo);
    if (ok != NULL) printf("%s", linha);
  } while (! feof(arquivo));

  fclose(arquivo);

}

A diferença em relação ao exemplo anterior está na sequência que lê as linhas do arquivo:

 do {
    ok = fgets(linha, 1024, arquivo); // Lê a próxima linha do arquivo
    if (ok != NULL) printf("%s", linha); // se conseguiu ler algo, mostra na tela
  } while (! feof(arquivo)); // para se chegou ao fim de arquivo

Há algumas novidades aqui:

  1. O valor de retorno de fgets é testado quanto a sua validade: a função fgets retorna o valor NULL se não conseguiu ler algo do arquivo. Isto pode ter ocorrido por um erro de leitura (ex: disco com defeito) ou porque se chegou ao fim do arquivo, e assim nada mais existe para ser lido. Esse teste aparece na linha:
    if (ok != NULL) printf("%s", linha)
    
    .
  2. A leitura continua enquanto não se chegar ao fim de arquivo: o teste de fim de arquivo se faz com a função int feof(FILE * arquivo), que retorna 0 se ainda não se chegou ao final do arquivo, ou 1 caso contrário. A chamada de feof se faz ao final do laço:
      } while (! feof(arquivo));
    

Escrevendo e lendo valores quaisqer

Como se viu, a escrita em arquivos pode ser feita com a função fprintf, que é similar a printf. Isto possibilita a escrita de qualquer tipo de valor em um arquivo, como se pode ver no próximo exemplo, em que se escreve uma contagem de 0 a 9 (um número por linha):

#include<stdio.h>

int main() {
  char nome[256];
  FILE * arquivo;
  int n;

  printf("Digite o nome de um arquivo: ");
  scanf("%s", nome);
  
  printf("\nVou gravar uma contagem numérica nesse arquivo\n");

  arquivo = fopen(nome, "w");
  if (arquivo == NULL) {
    perror("Ops ... erro ao acessar esse arquivo: ");
    return 1;
  }

  n = 0;
  while (n < 10) {
    fprintf(arquivo, "%d\n", n);
    n ++;
  }

  fclose(arquivo);

}

A contagem é gerada e escrita no arquivo nesta parte do programa:

  n = 0;
  while (n < 10) {
    fprintf(arquivo, "%d\n", n);
    n ++;
  }

Isto é quase o mesmo que escrever a contagem na tela usando-se printf. E fprintf realmente funciona exatamente da mesma forma que printf.

De forma análoga, a leitura de um arquivo que contém números (um por linha) pode ser feita com o programa abaixo:

#include<stdio.h>

int main() {
  char nome[256];
  FILE * arquivo;
  int n;
  int ok;

  printf("Digite o nome de um arquivo: ");
  scanf("%s", nome);
  
  printf("\nVou ler uma contagem numérica desse arquivo\n");

  arquivo = fopen(nome, "r");
  if (arquivo == NULL) {
    perror("Ops ... erro ao acessar esse arquivo: ");
    return 1;
  }

  do {
    ok = fscanf(arquivo, "%d", &n);
    if (ok > 0) printf("Leu: %d\n", n);
  } while (! feof(arquivo));

  fclose(arquivo);

}

A parte desse programa que lê os números contidos no arquivo é:

  do {
    ok = fscanf(arquivo, "%d", &n);
    if (ok > 0) printf("Leu: %d\n", n);
  } while (! feof(arquivo));

Pode-se ver que assim como existe fprintf, há a função fscanf, que funciona da mesma maneira que scanf. O programa desse exemplo funciona para qualquer arquivo que contenha números. Pode haver mais de um número por linha, contanto que estejam separados por espaços (não pode haver nada diferente de números e espaços). Finalmente, pode existir qualquer quantidade de linhas (experimente executar o programa !).

Lendo e escrevendo valores struct

#include<stdio.h>

struct Pessoa {
  char nome[1024];
  int idade;
  char cpf[12];
};

int main() {
  char path[256];
  FILE * arquivo;
  char opcao;
  struct Pessoa umaPessoa;

  printf("Digite o nome de um arquivo: ");
  scanf("%s", path);
  
  printf("\nVou gravar registros de pessoas nesse arquivo\n");

  arquivo = fopen(path, "w");
  if (arquivo == NULL) {
    perror("Ops ... erro ao acessar esse arquivo: ");
    return 1;
  }

  do {
    printf("Nome: ");
    scanf(" %[^\n]", umaPessoa.nome);
    printf("CPF (sem pontos ou traços): ");
    scanf("%s", umaPessoa.cpf);
    printf("Idade: ");
    scanf("%d", &umaPessoa.idade);

    fprintf(arquivo, "%s:%s:%d\n", umaPessoa.nome, umaPessoa.cpf, umaPessoa.idade);

    printf("Continuar (S/N) ?: ");
    scanf(" %c", &opcao);
  } while ((opcao == 'S') || (opcao == 's'));

  fclose(arquivo);

}