You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++读取超大输入文件异常:BST插入大文件首行未读取问题

大文件首行未被读取的BST程序问题

我用C++实现了一个从输入文件构建单词二叉搜索树(BST)的程序,输入文件格式如下:

i apple
i bakery
i collapse

其中命令"i"表示将后续单词插入BST。程序处理21个单词的小文件完全正常,但处理最多包含370100个单词的大文件时,首行似乎完全没被读取,找不到问题原因。相关代码如下:

class Node
{
    public:
        string word;
        Node *left, *right, *parent;

        Node() // 默认构造函数
        {
            left = right = parent = NULL; 
        }

        Node(string to_insert) 
        {
            word = to_insert;
            left = right = parent = NULL; 
        }
};

class BST
{
    private:
        Node *root; 
    public:
        BST(); 
        void insert(string);
        void insert(Node*, Node*);
        
};

BST :: BST()
{
    root = NULL;
}

void BST :: insert(string word)
{
    Node *to_insert = new Node(word); 
    if (root == NULL) 
        root = to_insert; 
    else
        insert(root,to_insert); 
}

void BST :: insert(Node* start, Node* to_insert)
{
    if (start == NULL)
        return;
    if (to_insert->word <= start->word)
    {
        if(start->left == NULL)
        {
            start->left = to_insert; 
            to_insert->parent = start; 
            return;
        }
        else // 需要递归调用
        {
            insert(start->left, to_insert);
            return;
        }
    }
    else // 插入节点的键更大,走右分支
    {
        if(start->right == NULL)
        {
            start->right = to_insert; 
            to_insert->parent = start; 
            return;
        }
        else 
        {
            insert(start->right, to_insert);
            return;
        }
    }
}

int main(int argc, char** argv)
{
    if (argc < 3) // 必须提供两个输入参数
    {
        throw std::invalid_argument("Usage: ./treewrapper <INPUT FILE> <OUTPUT FILE>"); // 抛出错误
    }

    ifstream input; // 输入文件流
    ofstream output; // 输出文件流

    input.open(argv[1]); // 打开输入文件
    output.open(argv[2]); // 打开输出文件

    string command; // 存储下一条命令和操作
    char *com, *dummy, *valstr, *op; // 用于strtok、strtol
    string val = ""; // 命令中的值

    BST myBST;

    int inserted = 0;

     while(getline(input,command))
    {
      cout << "Checking command" << "\n";
        if (command.length() == 0) // 命令为空
            continue;
        com = strdup(command.c_str()); // 复制字符串为C风格字符串
        op = strtok(com, " \t"); // 按空格/tab分割命令,第一个token是操作

        valstr = strtok(NULL, " \t"); // 下一个token是值,字符串形式
        cout << valstr << "\n";
        if(valstr != NULL) // 检查是否有可转换的值
            val = valstr; 
        
    
        if(strcmp(op,"i") == 0) // 插入列表
        {
            cout << "Insert "+ val << endl;
            myBST.insert(val);
            inserted++;
        }
     }
     cout << "Words inserted: " << to_string(inserted) << "\n";
     input.close();
     output.close();
}

问题根源

  1. 内存泄漏与strtok的状态异常:strdup分配的内存未释放,大文件循环会导致内存耗尽,引发程序异常中断,容易被误认为首行未读取;另外strtok依赖静态全局状态,大文件处理时可能出现解析异常。
  2. 文件打开状态未校验:如果大文件路径错误或权限不足,输入流打开失败但程序仍进入循环,自然无法读取首行。
  3. UTF-8 BOM干扰:部分大文件是带BOM的UTF-8格式,首行开头的3个隐藏字节(0xEF 0xBB 0xBF)会导致command解析异常,跳过首行插入逻辑。
  4. val的初始化逻辑漏洞:如果首行解析出valstr为空,val会保留上一次的空值,导致插入无效。

修复方案

核心修复点

  • 用C++的stringstream替换C风格的strtok和strdup,避免内存泄漏和状态异常;
  • 添加文件打开成功校验;
  • 处理UTF-8 BOM;
  • 优化命令解析逻辑,确保val仅在有效时被赋值。

修复后的main函数示例

int main(int argc, char** argv)
{
    if (argc < 3)
    {
        cerr << "Usage: ./treewrapper <INPUT FILE> <OUTPUT FILE>" << endl;
        return 1;
    }

    ifstream input(argv[1]);
    ofstream output(argv[2]);

    // 校验文件是否成功打开
    if (!input.is_open())
    {
        cerr << "无法打开输入文件: " << argv[1] << endl;
        return 1;
    }
    if (!output.is_open())
    {
        cerr << "无法打开输出文件: " << argv[2] << endl;
        return 1;
    }

    // 处理UTF-8 BOM
    char bom[3];
    input.read(bom, 3);
    if (!(bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF))
    {
        input.seekg(0); // 不是BOM格式,回到文件开头
    }

    string command;
    BST myBST;
    int inserted = 0;

    while (getline(input, command))
    {
        cout << "正在处理命令: " << command << "\n";
        if (command.empty())
            continue;

        stringstream ss(command);
        string op, val;
        ss >> op >> val;

        if (op == "i" && !val.empty())
        {
            cout << "插入: " << val << endl;
            myBST.insert(val);
            inserted++;
        }
    }

    cout << "已插入单词数: " << inserted << "\n";
    input.close();
    output.close();
    return 0;
}

内容的提问来源于stack exchange,提问作者first last

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 03:15:48