Respostas:
Primeiro, faça um ifstream
:
#include <fstream>
std::ifstream infile("thefile.txt");
Os dois métodos padrão são:
Suponha que cada linha consista em dois números e leia token por token:
int a, b;
while (infile >> a >> b)
{
// process pair (a,b)
}
Análise baseada em linha, usando fluxos de sequência:
#include <sstream>
#include <string>
std::string line;
while (std::getline(infile, line))
{
std::istringstream iss(line);
int a, b;
if (!(iss >> a >> b)) { break; } // error
// process pair (a,b)
}
Você não deve misturar (1) e (2), pois a análise baseada em token não devora novas linhas; portanto, você pode acabar com linhas vazias falsas se usar getline()
após a extração baseada em token o levar ao final de um linha já.
int a, b; char c; while ((infile >> a >> c >> b) && (c == ','))
while(getline(f, line)) { }
construto e sobre o tratamento de erros, consulte este (meu) artigo: gehrcke.de/2011/06/… (acho que não preciso ter má consciência postando isso aqui, é um pouco data esta resposta).
Use ifstream
para ler dados de um arquivo:
std::ifstream input( "filename.ext" );
Se você realmente precisa ler linha por linha, faça o seguinte:
for( std::string line; getline( input, line ); )
{
...for each line in input...
}
Mas você provavelmente só precisa extrair pares de coordenadas:
int x, y;
input >> x >> y;
Atualizar:
Em seu código você usa ofstream myfile;
, no entanto, o o
em ofstream
stands para output
. Se você quiser ler do arquivo (entrada), use ifstream
. Se você deseja ler e escrever, use fstream
.
A leitura de um arquivo linha por linha no C ++ pode ser feita de várias maneiras diferentes.
A abordagem mais simples é abrir um std :: ifstream e um loop usando chamadas std :: getline (). O código é limpo e fácil de entender.
#include <fstream>
std::ifstream file(FILENAME);
if (file.is_open()) {
std::string line;
while (std::getline(file, line)) {
// using printf() in all tests for consistency
printf("%s", line.c_str());
}
file.close();
}
Outra possibilidade é usar a biblioteca Boost, mas o código fica um pouco mais detalhado. O desempenho é bastante semelhante ao código acima (Loop com std :: getline ()).
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <fcntl.h>
namespace io = boost::iostreams;
void readLineByLineBoost() {
int fdr = open(FILENAME, O_RDONLY);
if (fdr >= 0) {
io::file_descriptor_source fdDevice(fdr, io::file_descriptor_flags::close_handle);
io::stream <io::file_descriptor_source> in(fdDevice);
if (fdDevice.is_open()) {
std::string line;
while (std::getline(in, line)) {
// using printf() in all tests for consistency
printf("%s", line.c_str());
}
fdDevice.close();
}
}
}
Se o desempenho for crítico para o seu software, considere usar a linguagem C. Esse código pode ser 4-5 vezes mais rápido que as versões C ++ acima, consulte a referência abaixo
FILE* fp = fopen(FILENAME, "r");
if (fp == NULL)
exit(EXIT_FAILURE);
char* line = NULL;
size_t len = 0;
while ((getline(&line, &len, fp)) != -1) {
// using printf() in all tests for consistency
printf("%s", line);
}
fclose(fp);
if (line)
free(line);
Fiz alguns benchmarks de desempenho com o código acima e os resultados são interessantes. Testei o código com arquivos ASCII que contêm 100.000 linhas, 1.000.000 de linhas e 10.000.000 de linhas de texto. Cada linha de texto contém 10 palavras em média. O programa é compilado com -O3
otimização e sua saída é encaminhada /dev/null
para remover a variável do tempo de registro da medição. Por último, mas não menos importante, cada parte do código registra cada linha com a printf()
função de consistência.
Os resultados mostram o tempo (em ms) que cada parte do código levou para ler os arquivos.
A diferença de desempenho entre as duas abordagens de C ++ é mínima e não deve fazer nenhuma diferença na prática. O desempenho do código C é o que torna o benchmark impressionante e pode mudar o jogo em termos de velocidade.
10K lines 100K lines 1000K lines
Loop with std::getline() 105ms 894ms 9773ms
Boost code 106ms 968ms 9561ms
C code 23ms 243ms 2397ms
std::cout
vs printf
.
printf()
função em todos os casos por consistência. Eu também tentei usar std::cout
em todos os casos e isso não fez absolutamente nenhuma diferença. Como acabei de descrever no texto, a saída do programa vai para /dev/null
que o tempo para imprimir as linhas não seja medido.
cstdio
. Você deveria ter tentado com a configuração std::ios_base::sync_with_stdio(false)
. Eu acho que você teria desempenhos muito melhores (ainda não é garantido, pois é definido pela implementação quando a sincronização é desativada).
Como suas coordenadas pertencem juntas como pares, por que não escrever uma estrutura para elas?
struct CoordinatePair
{
int x;
int y;
};
Em seguida, você pode gravar um operador de extração sobrecarregado para istreams:
std::istream& operator>>(std::istream& is, CoordinatePair& coordinates)
{
is >> coordinates.x >> coordinates.y;
return is;
}
E então você pode ler um arquivo de coordenadas diretamente em um vetor como este:
#include <fstream>
#include <iterator>
#include <vector>
int main()
{
char filename[] = "coordinates.txt";
std::vector<CoordinatePair> v;
std::ifstream ifs(filename);
if (ifs) {
std::copy(std::istream_iterator<CoordinatePair>(ifs),
std::istream_iterator<CoordinatePair>(),
std::back_inserter(v));
}
else {
std::cerr << "Couldn't open " << filename << " for reading\n";
}
// Now you can work with the contents of v
}
int
tokens do fluxo operator>>
? Como alguém pode fazê-lo funcionar com um analisador de operator>>
retorno (ou seja, quando falhar, reverta o fluxo para a posição anterior e retorne falso ou algo assim)?
int
tokens, o is
fluxo será avaliado false
e o loop de leitura terminará nesse ponto. Você pode detectar isso lá dentro operator>>
, verificando o valor de retorno das leituras individuais. Se você deseja reverter o fluxo, você ligaria is.clear()
.
operator>>
, é mais correto dizer is >> std::ws >> coordinates.x >> std::ws >> coordinates.y >> std::ws;
que, caso contrário, você está assumindo que seu fluxo de entrada está no modo de pular espaço em branco.
Expandir a resposta aceita, se a entrada for:
1,NYC
2,ABQ
...
você ainda poderá aplicar a mesma lógica, assim:
#include <fstream>
std::ifstream infile("thefile.txt");
if (infile.is_open()) {
int number;
std::string str;
char c;
while (infile >> number >> c >> str && c == ',')
std::cout << number << " " << str << "\n";
}
infile.close();
Embora não seja necessário fechar o arquivo manualmente, é uma boa ideia fazê-lo se o escopo da variável do arquivo for maior:
ifstream infile(szFilePath);
for (string line = ""; getline(infile, line); )
{
//do something with the line
}
if(infile.is_open())
infile.close();
Esta resposta é para o visual studio 2017 e se você quiser ler do arquivo de texto qual local é relativo ao seu aplicativo de console compilado.
primeiro, coloque seu arquivo de texto (test.txt neste caso) na pasta da solução. Após a compilação, mantenha o arquivo de texto na mesma pasta com applicationName.exe
C: \ Users \ "nome de usuário" \ source \ repos \ "solutionName" \ "solutionName"
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream inFile;
// open the file stream
inFile.open(".\\test.txt");
// check if opening a file failed
if (inFile.fail()) {
cerr << "Error opeing a file" << endl;
inFile.close();
exit(1);
}
string line;
while (getline(inFile, line))
{
cout << line << endl;
}
// close the file stream
inFile.close();
}
Esta é uma solução geral para carregar dados em um programa C ++ e usa a função readline. Isso pode ser modificado para arquivos CSV, mas o delimitador é um espaço aqui.
int n = 5, p = 2;
int X[n][p];
ifstream myfile;
myfile.open("data.txt");
string line;
string temp = "";
int a = 0; // row index
while (getline(myfile, line)) { //while there is a line
int b = 0; // column index
for (int i = 0; i < line.size(); i++) { // for each character in rowstring
if (!isblank(line[i])) { // if it is not blank, do this
string d(1, line[i]); // convert character to string
temp.append(d); // append the two strings
} else {
X[a][b] = stod(temp); // convert string to double
temp = ""; // reset the capture
b++; // increment b cause we have a new number
}
}
X[a][b] = stod(temp);
temp = "";
a++; // onto next row
}