Você está na página 1de 11

Renato Cardoso Mesquita

Departamento de Eng.
Elétrica da UFMG
renato@cpdee.ufmg.br

Programação Orientada a Objetos


em C++

5 -a . Manipulação de
arquivos em C++
. . . . . . . . . .
5-a. 1. Introdução à entrada e saída em arquivos em C++

• Os serviços de entrada e saída em C++ são implementados através da


biblioteca iostream, uma biblioteca que implementa uma hierarquia
de classes orientadas a objeto, que fazem uso de heranças simples e
múltiplas.

• Para utilizar os serviços desta biblioteca, é necessário usar :


#include <iostream>

• As operações de entrada e saída padrão são implementadas,


respectivamente, pelas classes istream e ostream. Os objetos cin, cout
e cerr pertencem a estas classes. Também existe a classe iostream,
derivada simultaneamente de istream e ostream, que implementa
operações de entrada e saída em um mesmo objeto.

• Para a entrada e saída de arquivos, existem as classes:

• ifstream, derivada de istream, que conecta um arquivo a um


programa, para entrada;

• ofstream, derivada de ostream, que conecta um arquivo a um


programa, para saída;
Outros mecanismos da linguagem C++ - Arquivos Pg. 2

• fstream, derivada de iostream, que conecta um arquivo a um


programa, para entrada e saída.

• Para poder utilizar a entrada e saída via arquivo, é necessário usar:


#include <fstream>

• Os operadores de fluxo de entrada >> e de saída << são suportados


nos objetos destas classes e podem ser sobrecarregados para efetuar a
entrada e saída de classes criadas pelo usuário.

• Para abrir um arquivo apenas para saída, definimos um objeto da


classe ofstream:
ofstream outFile ("copy.out", ios_base::out);
ofstream outFile2("teste.out");
Os argumentos passados para o construtor especificam o nome do
arquivo a ser aberto e o modo de abertura a ser usado. Um arquivo
de saída pode ser aberto no modo de saída, ios_base::out, ou
append, ios_ base::app. Por default, o arquivo é aberto no modo de
saída.

• Alguns compiladores mais antigos não conhecem a classe ios_base.


Se isto acontecer com seu compilador, substitua ios_base por ios.

• Se um arquivo já existente for aberto no modo saída, todo seu


conteúdo é eliminado. Se quisermos preservá-lo, devemos abri-lo no
modo append.

• Antes de tentar escrever ou ler em um arquivo, é sempre uma boa


idéia verificar se ele foi aberto sem problemas. Pode-se testá-lo
usando:
if(!outFile ) { // Abertura falhou ...
cerr << " copy.out não pode ser aberto para saída\n";
exit(-1);
}

• Como a classe ofstream é derivada de ostream, todas as operações


existentes em ostream (e portanto existentes em cout) podem ser
Outros mecanismos da linguagem C++ - Arquivos Pg. 3

aplicados em um objeto de ofstream, inclusive as operações de fluxo


de saída sobrecarregadas:
char ch = ' ';
string teste = "ABCTeste";
outFile.put( '1' ).put( ')' ).put( ch );
outFile << "1 + 1 = " << (1 + 1) << endl;
outFile << teste << endl;

• Para abrir um arquivo apenas para entrada, um objeto da classe


ifstream é utilizado. O programa abaixo lê um arquivo especificado
pelo usuário e o copia para a saída padrão e outro arquivo, também
especificado pelo usuário:
#include <fstream>
#include <string> // da STL ...
using namespace std;
int main()
{
cout << "Nome do arquivo de entrada: ";
string nome_arquivo_entrada;
cin >> nome_arquivo_entrada;
ifstream inFile (nome_arquivo_entrada.c_str( ) );
if(!inFile ) {
cerr << "Não foi possivel abrir o arquivo de entrada : "
<< nome_arquivo_entrada << " Saindo do programa!
\n";
return -1;
}
cout << "\nNome do arquivo de saída: ";
string nome_arquivo_saida;
cin >> nome_arquivo_saida;
ofstream outFile (nome_arquivo_saida.c_str( ) );
if(!outFile ) {
cerr << "Não foi possivel abrir o arquivo de saida : " <<
nome_arquivo_saida << " Saindo do programa! \n";
return -1;
}

char ch;
while (inFile.get(ch) ) {
Outros mecanismos da linguagem C++ - Arquivos Pg. 4

cout.put (ch);
outFile.put(ch);
}
}
• Objetos das classes ofstream e ifstream podem ser declarados sem
estarem associados a um arquivo. Um arquivo pode ser conectado
posteriormente, chamando a função membro open( );
• Um arquivo pode ser desconectado de um programa, chamando a
função membro close( );

#include <fstream>
using namespace std;
const int fileCnt = 5;
string fileTable [ fileCnt ] = { "JorgeAmado.txt",
"GuimaraesRosa.txt", "CarlosDrummond.txt", "RubemBraga.txt",
"ClariceLispector.txt" };

int main()
{
ifstream inFile; // não está associado a nenhum arquivo

for (int ix = 0; ix < fileCnt; ix++)


{
inFile.open (fileTable[ix].c_str() );
// ... Verifica se a abertura teve sucesso
// ... Processa o arquivo
inFile.close( );
}
}

• Um objeto da classe fstream pode abrir um arquivo tanto para saída


quanto para entrada. A classe fstream é derivada da classe iostream.

#include <fstream>
int main ()
{
fstream file;
int i, j, k;
file.open( "teste.txt", ios_base::in); // abertura para leitura
file >> i; // leitura usando file
// ...
Outros mecanismos da linguagem C++ - Arquivos Pg. 5

file.close();
// ...
file.open("teste.txt", ios_base::app);
file << endl << j << k <<endl;
file.close();
}

• Um objeto da classe fstream pode ser aberto para leitura e escrita


simultâneas:
fstream io ("teste.txt", ios_base::in | ios_base::app );

• O arquivo pode ser reposicionado usando as funções membro seekg()


ou seekp(). (o g indica posicionamento para buscar caracteres (g de
get) e o p indica posicionamento para armazenar caracteres (p de
put)). As funções podem ser usadas para fazer a movimentação para
uma "posição absoluta" ou para se deslocar de um "offset" em relação
a uma determinada posição.
seekg(pos_type posicao); // Vai para uma posição absoluta. 0 é a
posição de início do arquivo: especificado em bytes
seekg(off_type offset, ios_base::seekdir dir); // offset em relação a
alguma posição, em alguma direção

dir pode ser:


• ios_base::beg, início do arquivo;
• ios_base::cur, posição corrente do arquivo;
• ios_base::end, final do arquivo;

• Lembre-se que se seu compilador for antigo, você deve substituir


ios_base por ios .
• Supondo a leitura de registros com tamanho sizeof(Registro),
poderíamos posicionar o arquivo para leitura de cada um dos i
registros através de:

for (int i = 0; i < registroCont ; i++)


readFile.seekg(i*sizeof(Registro), ios_base::beg);

• Avanço de um registro em relação à posição corrente:

readFile.seekg(sizeof(Registro), ios_base::cur);

• Pode-se especificar um deslocamento negativo:


Outros mecanismos da linguagem C++ - Arquivos Pg. 6

readFile.seekg(-10, ios_base::cur);

• Pode-se obter a posição corrente de um arquivo com as funções


membro tellg() e tellp() (novamente, g = get e p = put). Por exemplo:

ios_base:: pos_type mark = writeFile.tellp(); // guarda posição


// ...
if(cancelEntry)
writeFile.seekp (mark); // retorna à posição armazenada
• Para compiladores mais antigos, substituir ios_base::pos_type por
streampos.

Exemplo: o programa abaixo lê um arquivo texto. Devemos calcular o


tamanho em bytes do arquivo e armazenar este valor no final do arquivo.
Além disto, cada vez que se encontrar um caracter de nova linha,
devemos armazenar o tamanho em bytes do início do arquivo até aquela
linha (incluindo o caracter de nova linha), no final do arquivo. Por
exemplo, dado o arquivo:
abcd
efg
hi
j

O resultado será:

abcd
efg
hi
j
5 9 12 14 24

#include <iostream>
#include <fstream>

using namespace std;


int main()
{
fstream inOut ("copy.out" , ios_base::in | ios_base :: app);
int cnt = 0; // Contador de bytes
char ch;
Outros mecanismos da linguagem C++ - Arquivos Pg. 7

inOut.seekg(0); /* como foi aberto no modo append, ele


estaria posicionado no final do arquivo à necessário
posicionar no início ! */

while (inOut.get (ch) )


{
cout.put( ch ); // Ecoa na saida
cnt++;
if ( ch == '\n' )
{
// Armazena a posição corrente

ios_base::pos_type mark = inOut.tellg();


inOut << cnt << ' ';
inOut.seekg (mark ); // Restaura a posição
}
}

// Ao final do loop acima, inOut encontrou o fim de arquivo.


// Portanto não está em estado que permita escrever o
// tamanho total. O estado deve ser restaurado com a função
// membro clear()

inOut.clear ();
inOut << cnt << endl;

cout << "\nTotal de caracteres: " << cnt << "\n" ;


return 0;
}

5-ª 2. Estados do fluxo


§ No exemplo final da seção anterior, usamos a função clear() para
restaurar o estado do arquivo, que se encontrava (eof) e não podia
mais ser escrito.
§ As bibliotecas de entrada e saída do C++ nos permitem verificar o
estado de cada fluxo de entrada e saída e desta forma sabermos se ele
está ou não em um estado de erro. Por exemplo, se escrevermos:

int ival;
cin >> ival;
Outros mecanismos da linguagem C++ - Arquivos Pg. 8

e teclarmos "Jorge Amado" como entrada, cin é colocado em


estado de erro. Uma operação de leitura somente será efetuada por
um fluxo de entrada que esteja em estado OK.
§ Para testar se um fluxo está em estado de erro, fazemos: if (!cin) ....
§ Um objeto de fluxo mantém um conjunto de flags de condição através
dos quais o estado do fluxo pode ser monitorado. Funções específicas
são usadas para verificar os estados:
§ eof() retorna verdadeiro se o fluxo encontrou o final do arquivo;
§ bad() retorna verdadeiro se houve uma tentativa de efetuar uma
operação inválida, como, por exemplo, efetuar um seek em uma
posição posterior ao final do arquivo;
§ fail() retorna verdadeiro se uma operação não obteve sucesso,
como, por exemplo, falha na tentativa de abertura de arquivo ou
erro no formato dos dados de entrada;
§ good() retorna verdadeiro se nenhuma das três condições
anteriores for verdadeira.
§ Existem dois métodos para modificar explicitamente o estado de um
objeto iostream. A função clear() reseta o estado. A função setstate()
adiciona determinada condição para o estado.
§ Os valores que podem ser utilizados em setstate são:
ios_base::badbit
ios_base::eofbit
ios_base::failbit
ios_base::goodbit
§ Para setar múltiplos estados, pode-se combiná-los através da operação
ou bit a bit: is.setstate( ios_base::badbit | ios_base::failbit);
§ A função clear pode também ser usada para limpar explicitamente um
determinado estado: cin.clear(ios_base::goodbit);
§ A função rdstate() permite acessar explicitamente o estado do objeto
para recuperação posterior:

ios_base::iostate old_state = cin.rdstate();


cin.clear();
process_input();

// Agora reseta cin para o valor antigo


cin.clear ( old_state);
Outros mecanismos da linguagem C++ - Arquivos Pg. 9

5-a. 3. Fluxos em strings

§ A biblioteca iostream permite operações em memória sobre objetos


string. Para utiliza-las é necessário incluir:

#include <sstream>

§ A função abaixo lê um arquivo texto em um objeto da classe string,


retornando o objeto. Supõe-se que o arquivo já esteja aberto.

#include <string>
#include <fstream>
#include <sstream>

string read_file_into_string(ifstream ifile)


{
ostringstream buf;
char ch;
while (buf && ifile.get (ch ) )
buf.put ( ch ); /* O buffer cresce na medida do
necessário para acomodar os caracteres de entrada */
return buf.str();
}

int main( )
{
cout << " Nome do arquivo a ser lido: ";
string nome_arquivo;
cin >> nome_arquivo;
ifstream arquivo(nome_arquivo.c_str());
if(!arquivo) {
cout << " Não consigo abrir o arquivo: " << nome_arquivo;
exit (-1);
}
string texto = read_file_into_string(arquivo);
cout << texto;
return 0;
}
Outros mecanismos da linguagem C++ - Arquivos Pg. 10

§ Pode-se escrever normalmente para um fluxo string, usando os


operadores de fluxo tradicionais e os sobrecarregados:

ostringstream saida;
saida << "Valor de i: " << i << " Valor de j: " << j << endl;
string msg = saida.str( );
cout << "Tamanho da string de mensagem: " << msg.size() << "
Mensagem: " << msg << endl;

§ Um istringstream lê a partir de um objeto string com o qual foi


construido. Um uso de istring é na transformação de uma string em
valores aritméticos. Exemplo:

string valores = "10 40 50 7.54";


istringstream str_entrada ( valores );
int i, j, k;
float x;
stringstream_entrada >> i >> j >> k >> x ;

5.a. 4. Formatação.

§ Cada classe das bibliotecas iostream mantém um "estado de


formatação" que controla os detalhes das operações de formatação.
Este estado pode ser alterado através de manipuladores ou de
sinalizadores de formato (uso das funções membro setf() e unsetf()),
como estudado no primeiro capítulo deste curso.
§ O conjunto completo de manipuladores, definido pela norma ANSI
C++ é apresentado na tabela abaixo. As opções em negrito são os
valores default. Não se esquecer de: #include <iomanip>

Manipulador Significado
boolalpha representa variáveis booleanas através de true e false
noboolalpha representa variáveis booleanas através de 0 e 1
showbase gera um prefixo indicando a base numérica
noshowbase não gera um prefixo indicando a base numérica
showpoint sempre gera um ponto decimal
noshowpoint somente mostra um ponto decimal com frações
showpos mostra o sinal + em números não negativos
Outros mecanismos da linguagem C++ - Arquivos Pg. 11

noshowpos não mostra o sinal + em números não negativos


skipws ignora os espaços em branco nos operadores de
entrada
noskipws não ignora os espaços em branco nos operadores de
entrada
uppercase imprime 0X em hexadecimal e E em notação científica
nouppercase imprime 0x em hexadecimal e e em notação científica
dec imprime em base 10
hex imprime em base hexadecimal
oct imprime em base octal
left adiciona caracteres de preenchimento a direita do valor
right adiciona caracteres de preenchimento a esquerda do
valor
internal adiciona caracteres de preenchimento entre o sinal e o
valor
fixed imprime pontos flutuantes em notação decimal
scientific imprime pontos flutuantes em notação científica
flush limpa o buffer de saída
ends insere um null e então limpa o buffer de saída
endl insere um newline e então limpa o buffer de saída
ws "come" os espaços em branco
setfill (ch) caracteres em branco serão preenchidos com ch
setprecision(n) precisão em ponto flutuante setada em "n"
setw(n) le ou escreve o valor em w caracteres
setbase(b) faz a saída de inteiros na base b

int i=10, j=20, k = 30;

cout << "i em decimal = " << i << " i em hexadecimal " << hex << i <<
flush;

Você também pode gostar