【问题标题】:Parsing large text file in C++ [closed]在 C++ 中解析大型文本文件 [关闭]
【发布时间】:2016-04-26 15:24:31
【问题描述】:

我有一个约 250k 行的文本文件。每行包含由多个空格和可能的其他符号分隔的数据。我想逐行解析数据,从每一行检索某些组件。

我编写了一个程序,它打开输入文件和输出文件,逐行解析输入文件,将行分解为适当的标记,并以所需格式重新构造新行并立即输出到输出文件中。

问题是,当我运行它时,它在解析 70 到 92k 行后停止。我所说的停顿是指程序仍在运行,但是它不处理任何内容,并且终端中的光标只是停留在那里并闪烁。通过使用愚蠢的调试(使用 cout),我检查了在第 92521 行附近它确实需要一个输入行(一个正确的行),但是它没有通过分解成标记和重建一个格式良好的行的部分并且只是停止。

下面我附上相关代码。我期待有人告诉我发生了什么,即为什么我的程序停滞不前以及我可以通过什么方式解决这个问题。感谢您的关注!

#include <iostream>
#include <fstream>
#include <cstring>
#include <sstream>

int main(int argc, char** argv) {
    std::ifstream inFile;
    std::ofstream outFile;
    std::string inDir("/home/marcin/jnp2/proj/data/oceny.txt");
    std::string outDir("/home/marcin/jnp2/proj/data/ocenyout.txt");
    outFile.open(outDir, std::ios::out | std::ios::app);
    inFile.open(inDir, std::ios::in);
    std::string line;
    int i = 1;
    while(std::getline(inFile, line, '\n')) {
    //for(int i = 0; i < 251819; i++) { // 197858
        //std::string line;
        //std::getline(inFile, line, '\n');
        //std::cout << "OK1" << std::endl;
        if(i == 92520) {
            int x;
            std::cin >> x;
        }
        if(!line.empty() && line[0] != '-' && line[0] != 'K' && line[0] != 'S') {
            //std::cout << line << std::endl;
            std::istringstream iss(line);
            std::string code, name, dyd_cycle, term, grade, person, tmp;
            iss >> code;
            std::size_t found;
            do {
                if(iss >> tmp) {
                    //iss >> tmp;
                    found = tmp.find("20");
                    if (found == std::string::npos)
                    if(name.empty())
                        name = tmp;
                    else
                        name = name + " " + tmp;
                    else
                        dyd_cycle = tmp;
                } else
                    return 42;
            } while (found == std::string::npos);
            //std::cout << "OK2" << std::endl;
            iss >> term;
            iss >> grade >> person;
            std::string formattedLine = code + ";" + name + ";" + dyd_cycle + ";" + term + ";" + grade + ";" + person;
            outFile << formattedLine << std::endl;
        }
        //std::cout << "OK3" << std::endl;
        std::cout << i++ << std::endl;
    }
    inFile.close();
    outFile.close();
    return 0;
}

编辑:最后一个输出停止在 “1000-621MRB;Metody realizacji baz danych;2004/TL;3;2;LONG_CODE_THAT_IM_NOT_SUPPOSED_TO_SHOW”。

我还要提一下,当我一点一点地做时,即前 50k 行,然后告诉程序(通过硬编码跳过前 50k 行)从 50k+1 行等开始没有问题- 我得到了我应该得到的确切输出。另一方面,当我告诉它每 50k 行关闭文件,重新打开它们并循环到输入文件的正确行时,我仍然遇到同样的问题。

Edit2:我将它编译到调试中并使用 gdb - 在关键行号周围它正确地获得了行(欢呼),但卡在了 iss >> 代码上。我在 CLion 中使用调试器,所以过了一会儿就超时了。

【问题讨论】:

  • 您是否尝试过使用真正的调试器闯入并查看发生了什么?
  • 那个内循环看起来很可疑。如果没有“20”次出现怎么办。我也不喜欢那个没有大括号的if
  • 发布它处理的最后一行的内容。另外,请修正你的缩进。
  • @MaxLybbert 也许如果他有一台内存很小的电脑。 250k*80B = 20MB 内存。
  • 您的do .. while 循环可能会无休止地运行。无论哪种方式,您都可能希望将其更改为 while (iss &gt;&gt; tmp) {

标签: c++ text-parsing data-processing


【解决方案1】:

使用 cout 并不总是最好的调试方法,因为我发现它有时会拖慢程序的终端/整体速度。您可以尝试使用断言或实际的调试器(例如 GDB)来调试您的程序。调试器将引导您完成代码,并准确地向您展示幕后发生的事情。

【讨论】:

  • 感谢您的建议。我再次尝试调试它,发现有一个错误的输入导致我的代码进入了一个永恒的循环。
  • 很高兴知道你想通了。如果您还没有回答,请务必对答案进行投票:)
  • 问题是我从很多人(加上你的)的 cmets 中收集了答案......我也不能投票,因为我还没有 15 个代表:/ 我会想向 5 个人提供答案,并感谢另外两个人对改进我的代码的建议。
  • 没问题!我正在尝试获得更多代表,以便我可以再次发布问题。确保您始终发布有意义的问题/答案;)
  • 明白。谢谢。
【解决方案2】:

我确实有一个错误的日期 - 对“20”的检查导致程序进入一个永恒的循环。我要感谢 pm100 和 George Sovetov 指出那段代码具有潜在危险。我使用调试器找到了问题 - 我感谢 Developer 和 pm100 建议这样做。感谢 gudok,我检查了 iss >> tmp 是否有效,这帮助我注意到我的循环会变得过于永恒。

我将修复代码并使用正则表达式来避免任何其他形式的此类错误(根据 knivil 的建议)。我还将使用 '\n' 而不是 std::endl,就像 kchinger 建议的那样。感谢所有cmets的家伙! :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-20
    • 1970-01-01
    相关资源
    最近更新 更多