Curso completo de linguagem C++
Gameprog - Escola de programação de jogos digitais
Contato: gameprog.br@gmail.com
track20.html

index << >>

20. Lendo e escrevendo em arquivos textos

20.1 Visão geral Neste capítulo você vai aprender como manipular arquivos textos para leitura e gravação. Geralmente vai surgir na sua experiência de programação a necessidade de ler e gravar informação em arquivos texto, por exemplo, gravar e ler dados de configuração do seu programa, dados das variáveis para rastreamento de erros entre muitas outras finalidades. Nosso programa ilustra leitura e gravação de dados de status de um jogo, processo usado tipicamente quando o jogador decide parar de jogar mas quer salvar o seu progresso para continuar mais tarde.
// arquivo_texto.cpp // Ilustra leitura e gravação de arquivos textos #include <iostream> // permite usar cin e cout #include <fstream> // permite ler e gravar arquivos #include <string> // vamos usar strings #include <cstdlib> // vamos gerar valor de energia aleatório #include <ctime> // vamos gerar valores aleatorios sempre diferentes using namespace std; // ****************** classe Config para dados de configuração do jogo ******** class Config { public: int m_fase; int m_estagio; int m_energia; string m_nome; // Nosso construtor Config (int fase = 1, int estagio = 0, int hp = 100, string snome = "Player") { m_fase = fase; m_estagio = estagio; m_energia = hp; m_nome = snome; } // ::Config().end // Mostra dados de status do jogo void mostrar() { char txt[255]; sprintf (txt, "\t(jogador:%s energia:%d tela:%d estagio:%d)", m_nome.c_str(), m_energia, m_fase, m_estagio); cout << txt << "\n"; } // ::mostrar().end // Resseta para os valores originais os dados de status do jogo void reset() { m_fase = 1; m_estagio = 0; m_energia = 100; m_nome = "Player"; } // ::reset().end }; // fim da classe config // -------------------------------------------------------------------------- // Protótipo das nossas funções básicas void inicio(); int menu(); void savegame (Config &cfg, string snome_arquivo); void loadgame (Config &cfg, string snome_arquivo); void mostra(Config &cfg); void fim(); // -------------------- inicio da funcao principal --------------------------- int main() { inicio(); int nEscolha; const int carregar = 1; const int gravar = 2; Config jogo_situacao (7,3,45, "Mario"); // gera um valor aleatorio na faixa 0-100 diferente a cada rodada do programa srand (time(0)); jogo_situacao.m_energia = rand() % 100; nEscolha = menu(); if ( nEscolha == gravar) { savegame(jogo_situacao, "savegame.txt"); jogo_situacao.mostrar(); } // endif gravando dados no disco if ( nEscolha == carregar) { jogo_situacao.reset(); cout << "\n\tDados atuais do registro: \n"; jogo_situacao.mostrar(); cout << "\n\tAgora, dados carregados do arquivo: \n"; loadgame(jogo_situacao, "savegame.txt"); jogo_situacao.mostrar(); } // endif carregando dados do disco fim(); } // endmain // ************ Implementação das funções definidas ************************* void inicio() { system("color f0"); system("title arquivo_texto.cpp"); cout << "\n"; } // fim da funcao inicio() void fim() { cout << "\n"; system("pause"); } // fim da funcao fim() // --------------- n = menu() gera um menu de escolhas ----------------------- int menu() { int nEscolha = 0; string txt_carregar = "\t 1- Carregar arquivo \n"; string txt_gravar = "\t 2- Gravar arquivo \n"; string txt_escolher = "\n\t------------------------ \n\t Digite sua escolha: "; cout << txt_carregar; cout << txt_gravar; cout << txt_escolher; cin >> nEscolha; return nEscolha; } // fim da funcao menu() // --------------- savegame() - grava no disco configuração do jogo ---------- void savegame (Config &cfg, string snome_arquivo) { ofstream hfile; hfile.open(snome_arquivo.c_str()); hfile << cfg.m_nome << "\n"; hfile << cfg.m_energia << "\n"; hfile << cfg.m_fase << "\n"; hfile << cfg.m_estagio << "\n"; hfile.close(); cout << "\n \t savegame() ok" << "\n"; } // savegame().fim // --------------- loadgame() - grava no disco configuração do jogo ---------- void loadgame (Config &cfg, string snome_arquivo) { ifstream hfile; hfile.open(snome_arquivo.c_str()); hfile >> cfg.m_nome; hfile >> cfg.m_energia; hfile >> cfg.m_fase; hfile >> cfg.m_estagio; hfile.close(); cout << "\t loadgame() ok" << "\n"; } // loadgame().fim
Bibliotecas <fstream> Esta é a biblioteca que você deve incluir para utilizar processos de leitura e gravação de dados em arquivos no disco ou pendrive. <cstdlib> Desta biblioteca aproveitamos as funções rand() e srand() para gerar um valor aleatório para a propriedade m_energia da situação do nosso jogo. <ctime> Desta biblioteca aproveitamos time() para prover rand() da capacidade de gerar números aleatórios diferentes a cada execução do programa. A classe Config A classe Config gera objetos contendo dados da situação do jogo: basicamente o nome do jogador, o quanto de energia que ele tem e aonde ele está: fase e subfase. A classe contém o método .mostrar() para exibir a configuração dessa situação, e contém o método .reset() para reconfigurar as propriedades com seus valores originais do início do programa.
PROPRIEDADES MÉTODOS
string m_nome
nome do jogador
.mostrar()
Mostra os dados de configuração
int m_energia
energia/saúde do jogador
.reset()
Resseta os dados de configuração para valores originais
int m_fase
fase principal
Config (fase, subfase, energia, nome)
Construtor da classe
int m_estagio
subfase da tela principal
***
Gravando dados no arquivo savegame.txt void savegame (Config &cfg, string snome_arquivo); Nesse protótipo definimos que nossa função de gravação savegame() vai receber a referência de um objeto Config (&cfg) e um nome de um arquivo estocado em uma string c++ (snome_arquivo). O processo de gravar dados em arquivos segue essa sequência: 1) criar um objeto arquivo da classe ofstream; 2) abrir o objeto arquivo; 3) configurar os dados a serem gravados nas variáveis; 4) gravar os dados com o objeto arquivo junto com o operador de inserção << 5) fechar o arquivo. Vejamos agora como implementar essas sequências com o c++. 1) criar um objeto arquivo: ofstream objArquivo; ofstream hfile; 2) abrir o objeto arquivo: objArquivo.open("nome_arquivo.txt"); hfile.open(snome_arquivo.c_str()); * Note que o método .open( char *sn) do objeto ofstream aceita como argumento apenas o tipo c-string ( char *sn) por isso utilizamos .c_str() que retorna nossa string c++ como uma c-string. 3) configurar os dados a serem gravados nas variáveis: int idade = 14; Config jogo_situacao (7,3,45, "Mario"); jogo_situacao.m_energia = 97; 4) gravar os dados utilizando o objeto arquivo com o operador de inserção <<: objArquivo << idade << "\n"; hfile << cfg.m_nome << "\n"; hfile << cfg.m_energia << "\n"; hfile << cfg.m_fase << "\n"; hfile << cfg.m_estagio << "\n"; 5) fechar o arquivo: objArquivo.close(); hfile.close(); Eis aqui nossa função completa para uma olhada na íntegra: // --------------- savegame() - grava no disco configuracao do jogo ---------- void savegame (Config &cfg, string snome_arquivo) { ofstream hfile; hfile.open(snome_arquivo.c_str()); hfile << cfg.m_nome << "\n"; hfile << cfg.m_energia << "\n"; hfile << cfg.m_fase << "\n"; hfile << cfg.m_estagio << "\n"; hfile.close(); cout << "\n \t savegame() ok" << "\n"; } // savegame().fim * Note que no final há o avanço de linha "\n", gravando assim cada tipo de dado em uma linha diferente do arquivo, procedendo dessa forma fica mais fácil para ler de volta os dados. Você deve observar a ordem na qual você está gravando os dados para depois lê-los também na mesma sequência. Lendo dados do arquivo savegame.txt void loadgame (Config &cfg, string snome_arquivo); Nesse protótipo definimos que nossa função de leitura loadgame() vai receber a referência de um objeto Config (&cfg) e um nome de um arquivo estocado em uma string c++ (snome_arquivo). O processo de ler dados de arquivos segue essa sequência: 1) criar um objeto arquivo da classe ifstream; 2) abrir o objeto arquivo; 3) declarar variáveis para receberem esses dados; 4) ler os dados com o objeto arquivo junto com o operador de extração >> 5) fechar o arquivo. Veja nossa função: // --------------- loadgame() - grava no disco configuracao do jogo ---------- void loadgame (Config &cfg, string snome_arquivo) { ifstream hfile; hfile.open(snome_arquivo.c_str()); hfile >> cfg.m_nome; hfile >> cfg.m_energia; hfile >> cfg.m_fase; hfile >> cfg.m_estagio; hfile.close(); } // loadgame().fim 20.2 Sintaxe alternativa de abertura de arquivo e verificações importantes 20.2.1 Sintaxe curta de abertura de arquivo No código acima abrimos nosso arquivo dessa forma: ifstream hfile; hfile.open("savetext.txt"); Estas duas linhas podem ser resumidas para esta forma: ifstream hfile("savetext.txt"); Na abertura do arquivo para gravação de dados o mesmo pode ser feito: ofstream hfile("savetext.txt"); 20.2.2 Verificando problema de arquivo Se houver problema na abertura do arquivo para leitura ou gravação, o objeto ifstream/ofstream é convertido para um tipo bool e retorna valor falso. É importante sempre fazer esta verificação antes de tentar leitura e gravação de dados. Em nosso exemplo, esssa verificação pode ficar dessa forma: if (!hfile) { cout << "Erro na abertura do arquivo. Saindo do programa... \n"; return -1; } 20.2.3 Verificando fim de arquivo Outra verificação importante é a de fim de arquivo que é realizada através do método .eof() do objeto ifstream/ofstream. Com muita frequência você vai pegar arquivos aonde o volume de dados é desconhecido e geralmente você vai utilizar uma estrutura de looping while para acessar todos esses dados. Você pode implementar uma leitura de grandes arquivos dessa forma: while (!hfile.eof()) { // leia os dados // use os dados } // fim do while Veja agora nosso programa exemplo xsave_text.cpp que ilustra o que dissemos acima:
// xsave_text.cpp // Ilustra leitura e gravação de arquivos textos // usando sintaxe alternativa // checando se fim de arquivo e se arquivo existe #include <iostream> // permite usar cin e cout #include <fstream> // permite ler e gravar arquivos #include <string> // vamos usar strings using namespace std; // -------------------- inicio da função principal --------------------------- int main() { system("color f0"); system("title xsave_text.cpp"); cout << "\n"; // Declarando variáveis int fase; int subfase, energia; string sjogador; // abrindo o arquivo... ifstream hfile("savegame.txt"); // O arquivo existe? if (!hfile) { cout << "erro na abertura do arquivo. Saindo... \n"; system("pause"); return -1; } // endif // Lendo os dados... while (!hfile.eof()) { hfile >> sjogador; hfile >> energia; hfile >> fase; hfile >> subfase; } // endwhile // mostrando os dados cout << "\t Nome do jogador: " << sjogador << "\n"; cout << "\t energia: " << energia << "\t"; cout << "\t fase: " << fase << "-" << subfase << "\n\n"; // fechando o arquivo hfile.close(); // Aproveitando o mesmo object ifstream para teste de arquivo inexistente hfile.open ("badfile.txt"); if (!hfile) cout << "\t o arquivo badfile.txt nao existe. Saindo... \n\n"; hfile.close(); cout << "\n"; system("pause"); } // endmain
Veja agora outro programa exemplo que carrega e mostra totalmente um arquivo texto. O destaque para este programa é para getline(hfile, slinha); que lê uma linha completa do arquivo e estoca-a na string slinha.
// showtextfile.cpp // Ilustra leitura e gravação de arquivos textos // usando sintaxe alternativa // checando se fim de arquivo e se arquivo existe #include <iostream> // permite usar cin e cout #include <fstream> // permite ler e gravar arquivos #include <string> // vamos usar strings using namespace std; // -------------------- inicio da função principal --------------------------- int main() { system("color f0"); system("title showtextfile.cpp"); cout << "\n"; // Declarando variáveis string slinha; // abrindo o arquivo... ifstream hfile("xsave_text.cpp"); // O arquivo existe? if (!hfile) { cout << "erro na abertura do arquivo. Saindo... \n"; system("pause"); return -1; } // endif // Lendo os dados... while (!hfile.eof()) { getline (hfile, slinha); cout << slinha << "\n"; } // endwhile // fechando o arquivo hfile.close(); cout << "\n"; system("pause"); } // endmain

index << >>


Produzido por Gameprog: Jair Pereira - Fev/2006 - Junho/2013 © gameprog.br@gmail.com http://www.gameprog.com.br