【问题标题】:Inconsistent results with fstream::read与 fstream::read 不一致的结果
【发布时间】:2018-05-17 05:43:56
【问题描述】:

我的程序使用小型 SQLite3 数据库。为了确保在程序启动时它确实存在,我在一个文件中有一个数据库创建脚本,它会被执行。

脚本运行没有问题。

但是,当使用 C++ I/O 函数从该文件中读取数据时,我经常在文件末尾收到无效字符,这导致脚本包含错误并且 SQLite 库无法正确执行。这是显示缓冲区内容时的示例: // Proper content from the file, then a random character is there 1 Error executing request: near "1": syntax error

其他字符也会出现,空格、数字、字母... 这是我加载脚本的代码:

std::cerr << "Creating database if needed...\n";
char sql_script[] = "/path/to/script.sql";
int script_length;
bool result = false;
std::ifstream script_fs(sql_script, std::fstream::binary | std::fstream::in);

if (script_fs) {
    char* buffer;
    char** err_msg = NULL;
    script_fs.seekg(0, script_fs.end);
    script_length = script_fs.tellg();
    script_fs.seekg(0, script_fs.beg);

    buffer = new char[script_length];
    script_fs.read(buffer, script_length);

    std::cout << "sql:\n" << buffer << "\n";

    if (sqlite3_exec(m_db, buffer, NULL, NULL, err_msg) == SQLITE_OK){
        result = true;
    } else {
        std::cerr << "Error executing: " << sqlite3_errmsg(m_db) << "\n" << err_msg << "\n";
    }
    delete buffer;
    script_fs.close();
} else {
    std::cerr << "Error opening script: " << strerror(errno) << "\n";
}

return result;
}

为什么会发生这种情况,我该如何解决?

【问题讨论】:

    标签: c++ io fstream


    【解决方案1】:

    您需要确保您有一个以 null 结尾的字符串。

    1. 为多一个字符分配内存。
    2. 将空字符分配给buffer 的最后一个元素。

    buffer = new char[script_length+1];
    script_fs.read(buffer, script_length);
    buffer[script_length] = '\0';
    

    另外,使用delete的数组形式。

    delete [] buffer;
    

    【讨论】:

    • 谢谢!这很奇怪,因为当脚本较短时,它每次都可以在没有空字节的情况下工作。你的回答解决了问题。
    • @user96649,这就是未定义行为的不幸之处。任何事情都可能发生,包括看似理智的行为。
    【解决方案2】:

    不要混合使用 C 和 C++,如果您想使用 ifstream 在 C++ 中读取 sql 查询文件,那么下面的 C++ 代码可能是您不需要管理内存的一种方法,请注意分配一个'\0' 等的额外字符:

    #include <iostream>
    #include <fstream>
    #include <vector>
    using namespace std;
    int main() {
      ifstream fin("test.sql", std::fstream::binary | std::fstream::in);
      std::string sqlquery = std::string(std::istreambuf_iterator<char>(fin), std::istreambuf_iterator<char>());
      std::cout<<sqlquery<<std::endl;
      return 0;
    }
    

    【讨论】:

    • 如果 sqlite3 API 允许,我会使用 std::string。据我所知,它不适用于 C++,所以我必须使用一个字符数组。
    • 您可以随时使用.c_str()字符串方法来实现。
    • 你说的完全正确,我没有想到这一点。我会纠正这个。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    • 2021-01-22
    • 1970-01-01
    • 1970-01-01
    • 2021-04-02
    • 2014-11-11
    • 1970-01-01
    相关资源
    最近更新 更多