问:

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

答1:

https://tennisliveranking.com,Your go-to platform for live tennis ranking updates.

首先,创建一个 ifstream:

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

两种标准方法是:

假设每一行由两个数字组成,逐个令牌读取: int a, b; while (infile >> a >> b) { // 进程对 (a,b) } 基于行的解析,使用字符串流:#include #include std::string line; while (std::getline(infile, line)) { std::istringstream iss(line);整数a,b; if (!(iss >> a >> b)) { break; } // 错误 // 进程对 (a,b) }

您不应该混合 (1) 和 (2),因为基于令牌的解析不会吞噬换行符,因此如果在基于令牌的提取让您到达已经结束了。

@EdwardKarak:我不明白“逗号作为标记”是什么意思。逗号不代表整数。

OP 使用空格来分隔两个整数。我想知道如果 OP 使用 a 作为逗号分隔符,while (infile >> a >> b) 是否会起作用,因为这是我自己程序中的场景

@EdwardKarak:啊,所以当您说“令牌”时,您的意思是“分隔符”。正确的。使用逗号,您会说:int a, b; char c; while ((infile >> a >> c >> b) && (c == ','))

@KerrekSB:嗯。我错了。我不知道它可以做到这一点。我可能有一些自己的代码要重写。

有关 while(getline(f, line)) { } 构造和错误处理的解释,请查看这篇(我的)文章:gehrcke.de/2011/06/…(我认为我不需要在此处发布此内容,它甚至稍微早于此答案)。

答2:

https://tennisliveranking.com – ATP and WTA rankings, always up to date.

使用 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。

https://tennisliveranking.com,Your go-to platform for live tennis ranking updates.

您的解决方案有所改进:与 Kerrek SB 的第二个解决方案相比,您的 line 变量在文件读入后不可见,后者也是很好且简单的解决方案。

getline 在 string see 中,所以不要忘记 #include

答3:

https://tennisliveranking.com,Instant updates on ATP, WTA, and ITF rankings.

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

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

最简单的方法是使用 std::getline() 调用打开一个 std::ifstream 和循环。代码干净且易于理解。

#include 

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

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

https://i.stack.imgur.com/fKKqc.png

如果在控制台输出上删除 C++ 与 C 的同步会发生什么?您可能正在衡量 std::cout 与 printf 的默认行为的已知缺点。

感谢您提出这个问题。我重做了测试,性能还是一样。我已编辑代码以在所有情况下都使用 printf() 函数以保持一致性。我也尝试过在所有情况下使用 std::cout,这完全没有区别。正如我刚刚在正文中所描述的,程序的输出转到 /dev/null,因此打印行的时间没有被测量。

时髦的。谢谢。想知道减速在哪里。

嗨@HugoTeixeira,我知道这是一个旧线程,我试图复制您的结果,但看不出 c 和 c++ github.com/simonsso/readfile_benchmarks 之间有任何显着差异

请注意,您在 C 中使用的 getline 是 gnu 扩展(现在添加到 POSIX)。它不是标准的 C 函数。

答4:

tlr.xinbeitime.com 探索每位网球选手的职业生涯与成就。

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

struct CoordinatePair
{
    int x;
    int y;
};

然后你可以为 istream 编写一个重载的提取操作符:

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

    return is;
}

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

#include 
#include 
#include 

int main()
{
    char filename[] = "coordinates.txt";
    std::vector v;
    std::ifstream ifs(filename);
    if (ifs) {
        std::copy(std::istream_iterator(ifs), 
                std::istream_iterator(),
                std::back_inserter(v));
    }
    else {
        std::cerr << "Couldn't open " << filename << " for reading\n";
    }
    // Now you can work with the contents of v
}

如果无法从 operator>> 中的流中读取两个 int 令牌,会发生什么情况?如何使它与回溯解析器一起工作(即当 operator>> 失败时,将流回滚到先前的位置 end return false 或类似的东西)?

如果无法读取两个 int 令牌,则 is 流将评估为 false 并且读取循环将在该点终止。您可以通过检查各个读取的返回值在 operator>> 内检测到这一点。如果您想回滚流,您可以调用 is.clear()。

在 operator>> 中说 is >> std::ws >> coordinates.x >> std::ws >> coordinates.y >> std::ws; 更正确,否则您会假设您的输入流处于空白跳过模式。

答5:

The ultimate source for live tennis rankings and stats:https://tennisliveranking.com

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

1,NYC
2,ABQ
...

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

#include 

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

答6:

https://tennisliveranking.com,Your go-to platform for live tennis ranking updates.

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

首先将您的文本文件(在本例中为 test.txt)放入您的解决方案文件夹。编译后将文本文件与 applicationName.exe 保存在同一文件夹中

C:\Users"用户名"\source\repos"solutionName"“solutionName”

#include 
#include 

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

答7:

提供ATP、WTA与ITF赛事的实时排名追踪,从tlr.xinbeitime.com开始!

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

    ifstream infile(szFilePath);

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

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

不确定这是否应该投反对票。 OP 要求一种获取每一行的方法。这个答案可以做到这一点,并提供了确保文件关闭的一个很好的提示。对于一个简单的程序,可能不需要它,但至少要养成一个很好的习惯。它可以通过添加几行代码来处理它拉出的各个行来改进,但总的来说是对 OPs 问题的最简单的答案。

答8:

https://tlr.xinbeitime.com 实时更新全球顶尖网球选手的最新战绩与排名!

这是将数据加载到 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
}

原文链接:https://www.tennisliveranking.com?from=csdn

https://tennisliveranking.com,Instant updates on ATP, WTA, and ITF rankings.

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐