在C++中使用ifstream逐行读取文件

file.txt内容如下:

5 3
6 4
7 1
10 5
11 6
12 3
12 4

其中5 3是一个坐标对。 如何在C++中逐行处理此数据?

我可以获取文件的第一行,但如何获取文件的下一行?

ifstream myfile;
myfile.open ("file.txt");
1816791 次浏览

使用ifstream从文件中读取数据:

std::ifstream input( "filename.ext" );

如果你真的需要逐行阅读,那么这样做:

for( std::string line; getline( input, line ); )
{
...for each line in input...
}

但您可能只需要提取坐标对:

int x, y;
input >> x >> y;

更新时间:

在您的代码中,您使用ofstream myfile;,但是ofstream中的o代表output。如果您想从文件(输入)中读取,请使用ifstream。如果您想同时读取和写入,请使用fstream

首先,创建一个ifstream

#include <fstream>
std::ifstream infile("thefile.txt");

这两种标准方法是:

  1. 假设每一行由两个数字组成,并逐个读取标记:

    int a, b;
    while (infile >> a >> b)
    {
    // process pair (a,b)
    }
    
  2. Line-based parsing, using string streams:

    #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)
    }
    

You shouldn't mix (1) and (2), since the token-based parsing doesn't gobble up newlines, so you may end up with spurious empty lines if you use getline() after token-based extraction got you to the end of a line already.

既然你的坐标是成对的,为什么不为它们写一个结构呢?

struct CoordinatePair
{
int x;
int y;
};

然后你可以为istreams编写一个重载的提取运算符:

std::istream& operator>>(std::istream& is, CoordinatePair& coordinates)
{
is >> coordinates.x >> coordinates.y;


return is;
}

然后您可以将坐标文件直接读取到向量中,如下所示:

#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
}

扩展接受的答案,如果输入是:

1,NYC
2,ABQ
...

您仍然可以应用相同的逻辑,如下所示:

#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();

虽然不需要手动关闭文件,但如果文件变量的范围更大,最好这样做:

    ifstream infile(szFilePath);


for (string line = ""; getline(infile, line); )
{
//do something with the line
}


if(infile.is_open())
infile.close();

在C++中逐行读取文件可以通过一些不同的方式完成。

[快速]使用std::getline()循环

最简单的方法是打开一个std::ifstream并使用std::getline()调用循环。

#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();
}

使用Boost的file_description_source

另一种可能性是使用Boost库,但代码变得更加冗长。性能与上面的代码非常相似(带有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();
}
}
}

[最快]使用C代码

如果性能对您的软件至关重要,您可以考虑使用C语言。此代码可以比上述C++版本快4-5倍,请参阅下面的基准测试

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);

基准——哪一个更快?

我用上面的代码做了一些性能基准测试,结果很有趣。我用包含100,000行,1,000,000行和10,000,000行文本的ASCII文件测试了代码。每行文本平均包含10个单词。该程序使用-O3优化编译,并将其输出转发到/dev/null,以便从测量中删除日志记录时间变量。最后但并非最不重要的是,为了一致性,每段代码都使用printf()函数记录每行。

结果显示了每段代码读取文件所需的时间(毫秒)。

两种C++方法之间的性能差异很小,在实践中不应该有任何区别。C代码的性能使基准测试令人印象深刻,并且可以在速度方面改变游戏规则。

                             10K lines     100K lines     1000K lines
Loop with std::getline()         105ms          894ms          9773ms
Boost code                       106ms          968ms          9561ms
C code                            23ms          243ms          2397ms

在此处输入图片描述

此答案适用于Visual Studio 2017,如果您想从文本文件中读取哪个位置相对于您编译的控制台应用程序。

首先将您的文本文件(test.txt在这种情况下)放入解决方案文件夹。编译后将文本文件保存在与applicationName.exe相同的文件夹中

C:\用户\"用户名"\源\存储库的\"解决方案名称"\"解决方案名称"

#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();
}

这是将数据加载到C++程序中的通用解决方案,并使用readline函数。这可以针对CSV文件进行修改,但分隔符在这里是空格。

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
}