C++ Ler e Escrever Arquivos
Tudo o que um programa guarda em variáveis some quando ele termina. A lista de compras, as notas da turma, o placar do jogo: fechou o programa, perdeu. Para guardar de verdade, o programa precisa escrever num arquivo, e da próxima vez, ler o arquivo. Em C++ isso é feito com a biblioteca <fstream>, e a boa notícia é que você já sabe usá-la: ela funciona igualzinho ao cout e ao cin.
- Como gravar texto num arquivo com
std::ofstreame<<. - A diferença entre sobrescrever e acrescentar (
std::ios::app). - Como ler um arquivo linha a linha com
std::getline, e palavra a palavra ou número a número com>>. - Como conferir se o arquivo abriu (
if (!arq)), e o que acontece quando você não confere. - Quando o arquivo é fechado, e a armadilha de ler um arquivo que ainda está aberto para escrita.
- Como ler a planilha
alunos.csvda Ana, separando os campos pela vírgula. - O básico de
std::filesystem: o arquivo existe? Qual o tamanho?
Todos os programas desta aula foram compilados com o g++ 15 na máquina fictícia da Ana, na pasta ~/cpp/arquivos, com o comando padrão do guia: g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa. Para ver o conteúdo dos arquivos, usamos o comando cat do terminal. No editor do guia, os arquivos de dados aparecem como abas ao lado do código.
A ideia: o arquivo é outro "terminal"
Você já conhece dois "canos" de texto: o std::cout, que leva texto do programa para a tela, e o std::cin, que traz texto do teclado para o programa. Em C++, esses canos se chamam streams ("fluxos"). Um arquivo é só mais um cano, com a ponta ligada no disco em vez da tela ou do teclado:
| Direção | Tela / teclado | Arquivo | Como usar |
|---|---|---|---|
| Programa → fora (escrever) | std::cout | std::ofstream | << |
| Fora → programa (ler) | std::cin | std::ifstream | >> e std::getline |
Os nomes se leem assim: ofstream = output file stream, "fluxo de saída para arquivo"; ifstream = input file stream, "fluxo de entrada de arquivo". Os dois moram no cabeçalho <fstream>.
1. Escrever: std::ofstream
#include <fstream>
#include <iostream>
int main() {
std::ofstream arq("compras.txt");
arq << "arroz\n";
arq << "feijão\n";
arq << "café " << 2 << " pacotes\n";
std::cout << "Lista gravada.\n";
}
- #include <fstream>
- Traz o
ofstreame oifstream. - std::ofstream arq("compras.txt");
- Cria uma variável
arqligada ao arquivocompras.txt, aberto para escrita. Se o arquivo não existe, ele é criado; se existe, é esvaziado. O nome é procurado na pasta em que o programa está rodando. - arq << "arroz\n";
- Escreve no arquivo, exatamente como o
coutescreveria na tela. O\npula a linha dentro do arquivo. - arq << "café " << 2 << " pacotes\n";
- Números, variáveis e encadeamentos funcionam igual ao
cout. - }
- No fim do
main, oarqdeixa de existir e o arquivo é fechado sozinho (seção 4).
$ g++ -std=c++23 -Wall -Wextra escrever.cpp -o escrever $ ./escrever Lista gravada. « só esta linha foi para a tela $ cat compras.txt arroz feijão café 2 pacotes $ ./escrever Lista gravada. $ cat compras.txt arroz « rodou duas vezes, mas a lista não duplicou feijão café 2 pacotes
Repare na segunda execução: o ofstream apagou o conteúdo antigo e escreveu tudo de novo. Esse é o comportamento padrão, chamado sobrescrever. Cuidado: abrir um arquivo importante com ofstream por engano apaga o que estava nele.
Acrescentar no fim: std::ios::app
Para um diário, um registro de vendas ou um placar, você quer o contrário: manter o que já existe e acrescentar no fim. Para isso, passe um segundo argumento, std::ios::app (de append, "anexar"):
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::string texto;
std::cout << "O que você fez hoje? ";
std::getline(std::cin, texto);
std::ofstream arq("diario.txt", std::ios::app);
arq << "- " << texto << '\n';
std::cout << "Anotado no diário.\n";
}
$ g++ -std=c++23 -Wall -Wextra diario.cpp -o diario $ echo "Estudei C++" | ./diario O que você fez hoje? Anotado no diário. $ echo "Fiz um bolo" | ./diario O que você fez hoje? Anotado no diário. $ cat diario.txt - Estudei C++ - Fiz um bolo « a segunda execução acrescentou, não apagou
O echo "…" | entrega o texto ao programa como se você o digitasse (por isso a resposta não aparece na tela). Se o diario.txt não existir, o std::ios::app o cria, como o modo normal.
| Abertura | Arquivo não existe | Arquivo já existe |
|---|---|---|
std::ofstream arq("x.txt"); | Cria | Apaga tudo e escreve do zero |
std::ofstream arq("x.txt", std::ios::app); | Cria | Mantém e escreve no fim |
2. Ler: std::ifstream
Linha a linha, com std::getline
A forma mais comum de ler um arquivo de texto é uma linha por vez, com o mesmo std::getline que você usou com o teclado (veja Ler uma Linha):
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream arq("compras.txt");
std::string linha;
int numero = 1;
while (std::getline(arq, linha)) {
std::cout << numero << ": " << linha << '\n';
++numero;
}
}
$ g++ -std=c++23 -Wall -Wextra ler.cpp -o ler $ ./ler 1: arroz 2: feijão 3: café 2 pacotes
- std::ifstream arq("compras.txt");
- Abre o arquivo para leitura. O arquivo não é alterado.
- std::getline(arq, linha)
- Lê uma linha inteira do arquivo (sem o
\ndo fim) e guarda emlinha. Igual aostd::getline(std::cin, linha), trocando o teclado pelo arquivo. - while (std::getline(arq, linha))
- O
getlinedevolve o próprioarq, que vale "verdadeiro" enquanto a leitura dá certo. Quando o arquivo acaba, a leitura falha e o laço para. Essa é a forma correta de ler "até o fim".
while (!arq.eof())
Você vai ver em código antigo um laço while (!arq.eof()) (end of file, "fim do arquivo") com o getline dentro. O mesmo ler.cpp escrito assim (eof.cpp) mostra uma linha a mais, vazia:
$ ./eof 1: arroz 2: feijão 3: café 2 pacotes 4: « linha fantasma
O eof() só fica verdadeiro depois que uma leitura bate no fim do arquivo. Na volta 4, o getline falhou, mas o corpo do laço rodou assim mesmo. Coloque a própria leitura na condição do while, como no ler.cpp.
Missão: o arquivo compras.txt está na outra aba. Complete o programa para ler o arquivo linha a linha com std::getline e contar quantos itens a lista tem. A saída deve ser A lista tem 5 itens.
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream arq("compras.txt");
if (!arq) {
std::cerr << "Erro: não consegui abrir compras.txt\n";
return 1;
}
std::string linha;
int itens = 0;
// leia o arquivo linha a linha, contando os itens
std::cout << "A lista tem " << itens << " itens\n";
}
arroz feijão café leite banana
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream arq("compras.txt");
if (!arq) {
std::cerr << "Erro: não consegui abrir compras.txt\n";
return 1;
}
std::string linha;
int itens = 0;
while (std::getline(arq, linha)) {
++itens;
}
std::cout << "A lista tem " << itens << " itens\n";
}
Palavra a palavra ou número a número, com >>
O >> funciona no arquivo como no cin (veja Entrada com cin): pula espaços e quebras de linha e lê um pedaço por vez. Com um std::string, cada pedaço é uma palavra:
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream arq("compras.txt");
std::string palavra;
int total = 0;
while (arq >> palavra) {
std::cout << '[' << palavra << ']';
++total;
}
std::cout << '\n' << total << " palavras\n";
}
$ g++ -std=c++23 -Wall -Wextra palavras.cpp -o palavras $ ./palavras [arroz][feijão][café][2][pacotes] 5 palavras
Com um double, cada pedaço é um número, e não importa como eles estão distribuídos nas linhas. O arquivo notas.txt tem duas notas na primeira linha e uma em cada uma das outras:
$ cat notas.txt 8.5 6.0 9.5 7
#include <fstream>
#include <iostream>
int main() {
std::ifstream arq("notas.txt");
double nota = 0.0;
double soma = 0.0;
int quantas = 0;
while (arq >> nota) {
soma += nota;
++quantas;
}
std::cout << quantas << " notas, média " << soma / quantas << '\n';
}
$ g++ -std=c++23 -Wall -Wextra numeros.cpp -o numeros $ ./numeros 4 notas, média 7.75
O while (arq >> nota) para quando o arquivo acaba ou quando aparece algo que não é número. Se o notas.txt tivesse a palavra falta no meio, a leitura pararia ali, sem aviso.
| Para ler… | Use | Exemplo |
|---|---|---|
| Linhas inteiras (com espaços) | std::getline(arq, linha) | Lista de compras, frases, CSV |
| Palavras soltas | arq >> palavra | Contar palavras de um texto |
| Números separados por espaço ou linha | arq >> numero | Uma lista de notas ou medidas |
3. O arquivo abriu? Sempre confira
Abrir um arquivo pode falhar: o nome está errado, o arquivo está em outra pasta, você não tem permissão. E o C++ não avisa sozinho. Veja o mesmo programa das notas, com o nome digitado errado (nota.txt em vez de notas.txt):
#include <fstream>
#include <iostream>
int main() {
std::ifstream arq("nota.txt");
double nota = 0.0;
double soma = 0.0;
int quantas = 0;
while (arq >> nota) {
soma += nota;
++quantas;
}
std::cout << quantas << " notas, média " << soma / quantas << '\n';
}
$ g++ -std=c++23 -Wall -Wextra semchecar.cpp -o semchecar $ ./semchecar 0 notas, média -nan $ echo $? 0 « para o sistema, deu tudo certo
Nenhuma mensagem de erro. O ifstream não conseguiu abrir, a primeira leitura falhou, o laço não rodou nenhuma vez e a conta 0.0 / 0 deu -nan (not a number, "não é um número"; veja float e double). Num programa maior, esse silêncio vira um relatório errado que ninguém percebe.
A solução é testar a variável logo depois de abrir. if (!arq) se lê "se o arquivo não está bom":
#include <fstream>
#include <iostream>
int main() {
std::ifstream arq("nota.txt");
if (!arq) {
std::cerr << "Erro: não consegui abrir nota.txt\n";
return 1;
}
double nota = 0.0;
double soma = 0.0;
int quantas = 0;
while (arq >> nota) {
soma += nota;
++quantas;
}
std::cout << quantas << " notas, média " << soma / quantas << '\n';
}
$ g++ -std=c++23 -Wall -Wextra checar.cpp -o checar $ ./checar Erro: não consegui abrir nota.txt $ echo $? 1 « código de erro: quem chamou o programa fica sabendo
- if (!arq)
- Um stream "vale falso" quando está com problema: não abriu, ou a última leitura falhou. Também existe a forma por extenso,
if (!arq.is_open())("não está aberto?"). - std::cerr
- A saída de erros (character error). Aparece na tela como o
cout, mas é um cano separado: se alguém mandar a saída normal do programa para um arquivo, as mensagens de erro continuam na tela. - return 1;
- Termina o
maincom o código 1, que no Linux quer dizer "deu errado" (o0é sucesso). Scripts e outros programas usam esse código para saber se você teve sucesso.
Escrever também pode falhar. O ofstream cria o arquivo, mas não cria pastas: se a pasta relatorios não existe, a abertura falha.
#include <fstream>
#include <iostream>
int main() {
std::ofstream arq("relatorios/maio.txt");
if (!arq) {
std::cerr << "Erro: não consegui criar relatorios/maio.txt\n";
return 1;
}
arq << "Vendas: 42\n";
}
$ ./gravarpasta Erro: não consegui criar relatorios/maio.txt $ echo $? 1
Regra: todo ifstream e todo ofstream são seguidos de um if (!arq). O C++ também pode avisar com uma exceção em vez de exigir o if; você vai conhecer exceções na próxima aula.
4. Fechar o arquivo
Você não precisa fechar o arquivo à mão. Quando a variável arq deixa de existir (no fim do bloco { } em que ela foi criada; veja Escopo), o arquivo é fechado sozinho. Esse jeito de amarrar um recurso a uma variável tem até nome, RAII, e você vai estudá-lo em Destrutores e RAII.
Existe o arq.close(), que fecha na hora. Ele é útil num caso específico: quando você escreveu e quer ler o mesmo arquivo na mesma função. Veja a armadilha:
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ofstream saida("recado.txt");
saida << "Volto às 15h\n";
std::ifstream entrada("recado.txt");
std::string linha;
if (std::getline(entrada, linha)) {
std::cout << "Li: " << linha << '\n';
} else {
std::cout << "O arquivo estava vazio!\n";
}
}
$ g++ -std=c++23 -Wall -Wextra fechar.cpp -o fechar $ ./fechar O arquivo estava vazio!
Mas o programa escreveu "Volto às 15h"! O que aconteceu: para ser rápido, o ofstream junta o texto numa área da memória chamada buffer ("reservatório") e só manda tudo para o disco de vez em quando, ou quando é fechado. Na hora da leitura, o saida ainda estava aberto e o texto ainda estava no buffer. A correção é fechar o arquivo antes de ler. Um jeito elegante é colocar a escrita num bloco próprio:
#include <fstream>
#include <iostream>
#include <string>
int main() {
{
std::ofstream saida("recado.txt");
saida << "Volto às 15h\n";
} // aqui o saida é fechado, e o texto vai para o disco
std::ifstream entrada("recado.txt");
std::string linha;
if (std::getline(entrada, linha)) {
std::cout << "Li: " << linha << '\n';
} else {
std::cout << "O arquivo estava vazio!\n";
}
}
$ g++ -std=c++23 -Wall -Wextra fechar2.cpp -o fechar2 $ ./fechar2 Li: Volto às 15h
Escrever saida.close(); antes de abrir o entrada também resolve. As duas formas funcionam; o bloco tem a vantagem de que o saida nem existe mais depois, então não dá para usá-lo fechado por engano.
Experimente: este programa escreve e lê o mesmo arquivo. Tire as chaves do bloco (as duas linhas com { e } sozinhas) e rode de novo para ver a armadilha do buffer. Depois coloque saida.close(); antes do ifstream e confira que volta a funcionar.
#include <fstream>
#include <iostream>
#include <string>
int main() {
{
std::ofstream saida("recado.txt");
saida << "Volto às 15h\n";
} // aqui o saida é fechado, e o texto vai para o disco
std::ifstream entrada("recado.txt");
std::string linha;
if (std::getline(entrada, linha)) {
std::cout << "Li: " << linha << '\n';
} else {
std::cout << "O arquivo estava vazio!\n";
}
}
5. Ler um CSV: a planilha da Ana
CSV (comma-separated values, "valores separados por vírgula") é o formato de planilha mais simples que existe: cada linha é um registro e os campos são separados por vírgulas. Qualquer planilha (LibreOffice Calc, Excel, Google Planilhas) salva e abre CSV. A Ana tem um na pasta Documentos:
$ cp ~/Documentos/alunos.csv . $ cat alunos.csv nome,idade,cidade,nota Ana,29,Recife,9.5 Bruno,34,Curitiba,7.0 Carla,22,Salvador,8.5 Diego,41,Manaus,6.0 Elisa,27,Porto Alegre,10.0
A primeira linha é o cabeçalho (os nomes das colunas). Para ler, o programa faz duas etapas: pega cada linha do arquivo com getline, e depois separa a linha nos campos, de vírgula em vírgula. Cada aluno vira uma struct:
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
struct Aluno {
std::string nome;
int idade = 0;
std::string cidade;
double nota = 0.0;
};
int main() {
std::ifstream arq("alunos.csv");
if (!arq) {
std::cerr << "Erro: não consegui abrir alunos.csv\n";
return 1;
}
std::vector<Aluno> turma;
std::string linha;
std::getline(arq, linha); // pula o cabeçalho
while (std::getline(arq, linha)) {
std::stringstream partes(linha);
std::string idade, nota;
Aluno a;
std::getline(partes, a.nome, ',');
std::getline(partes, idade, ',');
std::getline(partes, a.cidade, ',');
std::getline(partes, nota, ',');
a.idade = std::stoi(idade);
a.nota = std::stod(nota);
turma.push_back(a);
}
double soma = 0.0;
for (const auto& a : turma) {
std::cout << a.nome << " (" << a.cidade << "): " << a.nota << '\n';
soma += a.nota;
}
std::cout << "Média: " << soma / turma.size() << '\n';
}
$ g++ -std=c++23 -Wall -Wextra csv.cpp -o csv $ ./csv Ana (Recife): 9.5 Bruno (Curitiba): 7 Carla (Salvador): 8.5 Diego (Manaus): 6 Elisa (Porto Alegre): 10 Média: 8.2
- std::getline(arq, linha); // pula o cabeçalho
- Lê a primeira linha e não faz nada com ela. Sem isso, o programa tentaria transformar
"idade"em número. - std::stringstream partes(linha);
- Um stream de texto (do cabeçalho
<sstream>): transforma a linha num "arquivo de mentirinha", de onde dá para ler comgetlinee>>como de um arquivo de verdade. - std::getline(partes, a.nome, ',');
- O terceiro argumento muda o separador: em vez de ler até o fim da linha, o
getlinelê até a próxima vírgula. Cada chamada pega um campo. - std::stoi(idade) / std::stod(nota)
- Os campos chegam como texto.
std::stoiconverte paraintestd::stodparadouble(veja Texto ↔ Número).
Repare que a cidade Porto Alegre, com espaço, chegou inteira: o separador agora é a vírgula, não o espaço. Esse é o motivo de usar getline com ',' em vez de >>.
Este programa funciona para CSVs simples, como o da Ana. Planilhas exportadas às vezes trazem campos entre aspas com vírgulas dentro ("Silva, Ana"), ou usam ponto e vírgula como separador (comum em português, porque a vírgula é o separador decimal). Para esses casos, troque o separador (';') ou use uma biblioteca de CSV (veja Usar Bibliotecas Externas). E se uma linha tiver um número estragado, o std::stod lança uma exceção: tratar isso é assunto da próxima aula.
6. std::filesystem: perguntas sobre arquivos C++17
Às vezes você não quer ler o arquivo, só saber coisas sobre ele: existe? Qual o tamanho? Para isso existe a biblioteca <filesystem> ("sistema de arquivos"), do C++17. O nome é comprido, então é costume criar um apelido curto para ele, fs:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
for (const char* nome : {"alunos.csv", "compras.txt", "nota.txt"}) {
if (fs::exists(nome)) {
std::cout << nome << ": " << fs::file_size(nome) << " bytes\n";
} else {
std::cout << nome << ": não existe\n";
}
}
}
$ g++ -std=c++23 -Wall -Wextra fs.cpp -o fs $ ./fs alunos.csv: 132 bytes compras.txt: 30 bytes nota.txt: não existe
- namespace fs = std::filesystem;
- Um apelido para o namespace (a "família de nomes", veja Namespaces):
fs::existsé o mesmo questd::filesystem::exists. É parecido com o using para tipos. - fs::exists(nome)
- Verdadeiro se o arquivo (ou pasta) existe.
- fs::file_size(nome)
- O tamanho em bytes. A
compras.txttem 28 caracteres (contando as 3 quebras de linha), mas 30 bytes: oãe oéocupam 2 bytes cada em UTF-8 (veja Acentos e UTF-8).
Pergunte exists antes de file_size. Pedir o tamanho de um arquivo que não existe derruba o programa:
$ ./fserro terminate called after throwing an instance of 'std::filesystem::__cxx11::filesystem_error' what(): filesystem error: cannot get file size: No such file or directory [nota.txt] Abortado (imagem do núcleo gravada) ./fserro $ echo $? 134
O file_size lançou uma exceção (No such file or directory = "arquivo ou diretório inexistente"), ninguém a tratou e o programa foi abortado. Você vai aprender a ler e a evitar essa mensagem na aula de Exceções.
A biblioteca faz muito mais (criar pastas com fs::create_directories, listar arquivos de uma pasta, copiar, apagar, renomear), mas isso foge do básico. Por enquanto, guarde exists e file_size.
Quando dá errado
O que aconteceu: o arquivo não abriu (nome errado, pasta errada) e você não conferiu. Laços de leitura simplesmente não rodam.
Como confirmar: acrescente if (!arq) { std::cerr << "não abriu\n"; return 1; } logo depois de abrir. Confira em que pasta você está rodando o programa (pwd, no terminal): o nome é procurado ali, não na pasta do .cpp.
Como resolver: corrija o nome ou use o caminho completo, como "/home/ana/Documentos/alunos.csv".
O que aconteceu: você abriu com std::ofstream arq("dados.txt"), que esvazia o arquivo na hora de abrir, mesmo que você não escreva nada.
Como resolver: para acrescentar, use std::ios::app. Para só ler, use std::ifstream.
O que aconteceu: o ofstream ainda estava aberto, e o texto ainda estava no buffer (seção 4).
Como resolver: feche antes de ler (saida.close();) ou coloque a escrita num bloco { } próprio.
O que aconteceu: o laço foi escrito com while (!arq.eof()). Com getline, aparece uma linha vazia no fim; com >>, a leitura que falha deixa a variável como estava, e o último número entra duas vezes na conta. O numeros.cpp escrito assim deu 5 notas, média 7.6 em vez de 4 notas, média 7.75.
Como resolver: coloque a leitura na condição: while (std::getline(arq, linha)) ou while (arq >> x).
O que aconteceu: um campo que deveria ser número não era (o cabeçalho que você esqueceu de pular, um campo vazio, uma vírgula a mais). O std::stoi/std::stod não conseguiu converter e lançou uma exceção.
Como resolver: pule o cabeçalho com um getline antes do laço e trate o erro com try/catch (veja Exceções).
Referência rápida
| Escrita | Significado |
|---|---|
#include <fstream> | Traz std::ofstream e std::ifstream. |
std::ofstream arq("x.txt"); | Abre para escrever, apagando o conteúdo antigo. |
std::ofstream arq("x.txt", std::ios::app); | Abre para escrever no fim, mantendo o conteúdo. |
arq << texto << '\n'; | Escreve, como o cout. |
std::ifstream arq("x.txt"); | Abre para ler. |
if (!arq) { … } | Não abriu (ou a última leitura falhou). |
while (std::getline(arq, linha)) | Lê linha a linha até o fim. |
while (arq >> x) | Lê palavra a palavra ou número a número. |
std::getline(partes, campo, ',') | Lê até a próxima vírgula (com std::stringstream, de <sstream>). |
arq.close(); | Fecha na hora (normalmente o fim do bloco já fecha). |
std::filesystem::exists("x.txt") | O arquivo existe? (C++17, <filesystem>) |
std::filesystem::file_size("x.txt") | Tamanho em bytes (exceção se não existir). |
Exercícios
1. Abrir para acrescentar
Complete para abrir vendas.txt sem apagar o que já está nele:
2. Conferir a abertura
Complete a condição que detecta que o arquivo não abriu:
if () { std::cerr << "Erro\n"; return 1; }
3. Separar por ponto e vírgula
Um CSV usa ; como separador. Complete para ler o primeiro campo da linha:
4. O arquivo placar.txt tem 10 linhas. O que sobra nele depois de std::ofstream arq("placar.txt"); arq << "fim\n";?
5. O ifstream não encontrou o arquivo e o programa não conferiu. O que acontece no while (std::getline(arq, linha))?
Missão final: quem passou?
Missão: o programa já abre o alunos.csv (na outra aba), pula o cabeçalho e lê o nome de cada aluno. Separe os outros três campos (idade, cidade e nota) com std::getline(partes, …, ','), converta a nota com std::stod e, se ela for 7.0 ou mais, mostre o nome e conte o aluno. No fim deve aparecer Aprovados: 4.
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::ifstream arq("alunos.csv");
if (!arq) {
std::cerr << "Erro: não consegui abrir alunos.csv\n";
return 1;
}
std::string linha;
std::getline(arq, linha); // pula o cabeçalho
int aprovados = 0;
while (std::getline(arq, linha)) {
std::stringstream partes(linha);
std::string nome, idade, cidade, nota;
std::getline(partes, nome, ',');
// separe os outros três campos e, se a nota for 7 ou mais,
// mostre o nome e conte mais um aprovado
}
std::cout << "Aprovados: " << aprovados << '\n';
}
nome,idade,cidade,nota Ana,29,Recife,9.5 Bruno,34,Curitiba,7.0 Carla,22,Salvador,8.5 Diego,41,Manaus,6.0 Elisa,27,Porto Alegre,10.0
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::ifstream arq("alunos.csv");
if (!arq) {
std::cerr << "Erro: não consegui abrir alunos.csv\n";
return 1;
}
std::string linha;
std::getline(arq, linha); // pula o cabeçalho
int aprovados = 0;
while (std::getline(arq, linha)) {
std::stringstream partes(linha);
std::string nome, idade, cidade, nota;
std::getline(partes, nome, ',');
std::getline(partes, idade, ',');
std::getline(partes, cidade, ',');
std::getline(partes, nota, ',');
if (std::stod(nota) >= 7.0) {
std::cout << nome << '\n';
++aprovados;
}
}
std::cout << "Aprovados: " << aprovados << '\n';
}
Resumo
- Arquivos são streams, como
coutecin:std::ofstream+<<para escrever,std::ifstream+getline/>>para ler. Tudo em<fstream>. std::ofstreamapaga o conteúdo antigo; comstd::ios::app, acrescenta no fim.- Leia até o fim com a leitura na condição:
while (std::getline(arq, linha)). Nada deeof(). - Sempre confira se abriu:
if (!arq). Sem isso, o erro passa em silêncio. - O arquivo fecha sozinho no fim do bloco. Para ler o que acabou de escrever, feche antes (
close()ou um bloco). - CSV:
getlinepega a linha;std::stringstream+getline(…, ',')separa os campos;stoi/stodconvertem. std::filesystem::existsefile_sizerespondem perguntas sobre o arquivo sem abri-lo.