Agnor's HQ

Aula 08 - Escrita e Leitura em Ficheiros - Introdução

Conceitos-Chave:

- fstream, biblioteca standard do C++ para leitura e escrita em ficheiros
- ofstream, para escrita em ficheiros
- ifstream, para leitura em ficheiros
- getline(), função para receber uma frase do utilizador (cin.getline) ou de um ficheiro (ifstream::getline)

Escrita e Leitura em Ficheiros

A leitura (e escrita) de ficheiros tornou-se essencial em programação de jogos, por exemplo na construção de mapas e para guardar o percurso do jogador no jogo.
Durante esta lição vamo-nos concentrar no básico da escrita e leitura em ficheiros. O carregamento de mapas e tratamento de dados virá depois. 

Para podermos ter acesso à leitura (ou escrita) de ficheiros teremos que usar a biblioteca fstream (file stream). A melhor forma de explicar o básico da escrita/leitura em ficheiros é com um programa:

#include <iostream>
#include <fstream>  //inclui a biblioteca fstream, para usar o ofstream e ifstream
using namespace std;

int main()
{
    // para escrita a instrução é ofstream variavel("nome_do_ficheiro.txt)
    ofstream doc_out("save.txt"); //abre o ficheiro save.txt para escrita

    // para leitura a instrução é ifstream variavel("nome_do_ficheiro.txt)
    ifstream doc_in("save.txt"); //abre o ficheiro save.txt para leitura

    char aux[50]; //cria um array com capacidade para 50 caracteres

    doc_out << "Nivel:1\n" << "Nick:Agnor" << endl;

    doc_out.close();    //não se esqueçam de fechar os ficheiros de escrita!!!!

    while (doc_in >> aux) //enquanto o conteúdo do documento não for transferido para o aux...
    {
        cout << aux << endl;     //...imprime no ecrã as palavras.
    }

    //notem que o ficheiro de leitura não necessita de ser fechado

    cin.get();
    return 0;
}

Exemplo 8.1 - Escrever e Ler num ficheiro de texto

Vamos por partes:

ofstream

ofstream significa output file stream e serve para a escrita em ficheiros. Antes de poder escrever alguma coisa, temos que definir em que ficheiro queremos guardar o texto: ofstream nome_da_variavel(nome_do_ficheiro). Tanto o ofstream e o ifstream pertencem à bilbioteca fstream, que tem de ser incluída no programa ( #include <fstream>). De notar que todos os ficheiros de escrita necessitam de ser fechados, quando não precisarmos mais deles (usando o close() ).

ifstream

ifstream serve para a leitura de ficheiros (input file stream). Define-se como a biblioteca ofstream: ifstream nome_da_variavel(nome_do_ficheiro)

Dica:

Para aceder a um ficheiro de texto que esteja dentro de uma pasta, temos de separar o nome da pasta do nome do ficheiro, através de uma barra '/'. Por exemplo: ofstream mapa("mapas/nivel1.map");

doc_out << string; e doc_in >> string;

Enviamos texto para um ficheiro da mesma forma que enviamos para o console output e lemos um ficheiro da mesma forma que o lemos através do console input. Neste exemplo:

doc_out << "Nivel:1" <<- estamos a enviar a string "Nivel:1" e o comando endl (para mudar de linha) para o doc_out, ou seja, para o ficheiro identificado por doc_out (save.txt).

doc_in >> aux - estamos a enviar o conteúdo de doc_in (apenas a primeira palavra) para a string aux.

doc_out.close()

Sempre que acabarmos de escrever no ficheiro, temos de fechá-lo. Para tal existe a função close() dentro da biblioteca fstream. Notem que é utilizado um '.' (ponto) para unir o doc_out à "função" close(). Isto será explicado quando falarmos de classes.

while (doc_in >> aux)

Como ao fazermos doc_in >> aux só é transferida a primeira palavra para o output, temos de criar um loop. A expressão (doc_in >> aux) vai ser verdadeira quando chegar ao fim do ficheiro. Então, enquanto não chegar ao fim do ficheiro, será executada o doc_in >> aux e será mostrado no cout o conteúdo de aux. Como cada vez que fazemos doc_in >> aux este avança para a palavra seguinte, é mostrado o conteúdo todo do ficheiro, palavra por palavra.

Usar cin.getline()

O uso de cin.getline() pode-vos parecer totalmente fora do assunto da lição, mas depois perceberão porque o pus aqui.

Até agora, já devem ter reparado que num programa que receba dados do utilizador através de cin (console input), só receberão uma palavra e não uma frase. O cin.getline() , como o próprio nome indica, recebe uma linha do utilizador. O protótipo da função é:

cin.getline(char *buffer, int length, char terminal_char);

O char *buffer será a string (conjunto de carácteres) onde será armazenado o input, a lenght será o tamanho da string e o último será o carácter terminador. O carácter terminador está predefenido como \n ou seja, quando a frase acabar.

Devem notar que há um asterisco (*) antes da variável buffer. Isso é uma declaração de um apontador (que será explorado na aula 11. O uso de apontadores (char* buffer) permite-nos criar uma string, sem que seja necessário definir um número de caracteres específicos
O último parâmetro é opcional, e na maior parte das vezes pode ser ignorado. Vejam um exemplo de uso com a função:

#include <iostream>
using namespace std;

int main()
{
    char nome[150]; //cria uma variável capaz de conter 150 caracteres
    cout << "Insira o seu nome completo:" << endl;
    cin.getline(nome, 150);

    cout << "O seu nome e: " << nome << endl;

    cin.get();
    return 0;
}

Exemplo 8.2 - Uso de cin.getline()

Deve ser o suficiente para perceberem, no entanto qualquer dúvida e contactem-me.

Ler linhas de ficheiros

Para ler linhas em ficheiros a função é exactamente a mesma, só que aplicada de maneira diferente. Por exemplo:

ifstream doc_in("save.txt");
doc_in.getline(variavel, 200);

Difícil? Nem por isso :P

Sempre que usarmos a função getline(); o ficheiro avança para a próxima linha (em vez de avançar para a próxima palavra). Experimentem o código abaixo:

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    char aux[150]; //cria uma variável capaz de conter 150 caracteres, para a escrita
    char boas_vindas[150];
    char nome[150];
    char idade[4];  //só contem 4 carácteres, não é preciso mais para a idade
    //notem que é do tipo char e não int... um problema a ser explorado em aulas mais avançadas

    ifstream doc_in("save.txt");
    ofstream doc_out("save.txt");

    doc_out << "Bemvindo ao Programa" << endl;  /*a mensagem de boas-vindas não pode ser personalizada
                                                pelo utilizador, mas só pelo programador*/
    cout << "Insira o seu nome: " << endl;
    cin.getline(aux, 150);

    doc_out << aux << endl;

    cout << "Insira a sua idade: " << endl;
    cin >> aux;

    doc_out << aux << endl;

    doc_out.close();    //fecha o documento

    doc_in.getline(boas_vindas, 150);   //cada vez que faz a chamada à função muda-se de linha
    doc_in.getline(nome, 150);
    doc_in.getline(idade, 4);

    cout << boas_vindas << " " << nome << ", " << idade << " anos" << endl;

    system("PAUSE");
    return 0;
}

Exemplo 8.3 - Mensagem de Boas-Vindas 2.0

Não necessita de muitas explicações. Há alguns problemas com este código que impedem de ser uma forma viável de salvar jogos, mas serão explorados (e resolvidos espero :) em futuras lições.

Um bom exercício seria separar o programa, criando uma versão que serviria somente para criar o ficheiro de texto, e outra para lê-lo, seria uma versão bastante primitiva de um editor de níveis.

Final da aula 08 de C++:

Próxima aula -> C++ 09 - Leitura e Escrita em Ficheiros de Texto - Introdução

Fazer o download do código fonte dos exemplos da aula WinZip
Fazer o download da aula em PDF (Brevemente)

Ir para o topo da página

Aulas de C++

Anúncios