C++操作SQLite3插入俄文数据为空的编码问题求助
解决SQLite3插入俄文姓名为空的编码问题
你遇到的俄文姓名插入为空的问题,核心是控制台输入缓冲区混乱+SQLite文本编码绑定的细节问题,以下是具体解决方案:
1. 修复控制台输入的缓冲区冲突
代码中混用wcin.getline()和cin >> age会导致输入缓冲区残留换行符,下一次getline会直接读取空字符串,最终插入的name就是空值。
解决方法:在cin >> age后添加缓冲区清理代码,记得包含<limits>头文件:
cin >> age; // 清理输入缓冲区的换行符,避免影响下一次getline cin.ignore(numeric_limits<streamsize>::max(), '\n');
2. 确保SQLite数据库以UTF-8编码打开
虽然SQLite默认用UTF-8,但显式指定编码可以避免旧数据库的编码兼容问题,将sqlite3_open替换为sqlite3_open_v2:
int open_db = sqlite3_open_v2("test.db", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, "UTF-8"); // 明确指定UTF-8编码
3. 改用UTF-8字符串绑定(更稳定的方案)
sqlite3_bind_text16依赖系统宽字符编码(Windows是UTF-16LE),换成UTF-8字符串绑定兼容性更好。可以将wstring转换为UTF-8编码的string,再用sqlite3_bind_text绑定:
首先添加转换逻辑:
// 把wstring转换为UTF-8 string std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_converter; std::string utf8_name = utf8_converter.to_bytes(name);
然后修改SetDB函数的绑定代码:
// 替换原有的sqlite3_bind_text16 sqlite3_bind_text(*stmt, 1, utf8_name.c_str(), -1, SQLITE_TRANSIENT);
注意:用
SQLITE_TRANSIENT代替SQLITE_STATIC,因为转换后的UTF-8字符串是局部变量,需要SQLite自行复制数据。
修改后的完整代码
#include <iostream> #include <sqlite3.h> #include <string> #include <locale> #include <codecvt> #include <Windows.h> #include <limits> // 新增头文件,用于清理缓冲区 // 定义控制台颜色宏(原代码中缺失,补充) #define RED "\033[31m" #define GREEN "\033[32m" #define RESET "\033[0m" // 补充原代码中缺失的ERRORsql函数 void ERRORsql(int open_result, sqlite3* db) { if (open_result != SQLITE_OK) { std::cerr << RED << "Ошибка открытия базы данных: " << sqlite3_errmsg(db) << RESET << std::endl; sqlite3_close(db); exit(EXIT_FAILURE); } } using namespace std; void CreateTable(int open, sqlite3* db, char* ERR) { cout << "Создание таблицы: "; const char* SQLTable = "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT NOT NULL, Age INTEGER);"; open = sqlite3_exec(db, SQLTable, 0, 0, &ERR); if (open) { cerr << RED << "ПРОВАЛ" << ERR << endl << RESET; sqlite3_free(ERR); } else cout << GREEN << "УСПЕХ" << RESET << endl; } void SetDB(sqlite3* db, const wstring& name, int age, sqlite3_stmt** stmt) { const char* insertSQL = "INSERT INTO users (Name, Age) VALUES (?, ?)"; if (sqlite3_prepare_v2(db, insertSQL, -1, stmt, nullptr) == SQLITE_OK) { // 将wstring转换为UTF-8编码的string wstring_convert<codecvt_utf8<wchar_t>> utf8_converter; string utf8_name = utf8_converter.to_bytes(name); // 使用UTF-8字符串绑定 sqlite3_bind_text(*stmt, 1, utf8_name.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_int(*stmt, 2, age); if (sqlite3_step(*stmt) != SQLITE_DONE) cerr << "Вставка данных: " << RED << "ПРОВАЛ" << endl << sqlite3_errmsg(db) << RESET; else cout << "Вставка данных: " << GREEN << "УСПЕХ" << endl << RESET; } else { cerr << "Подготовка запроса: " << RED << "ПРОВАЛ" << RESET << endl; } sqlite3_finalize(*stmt); } int main() { SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); setlocale(LC_ALL, "ru_RU.UTF-8"); // 明确指定UTF-8区域设置 wstring name; int age; sqlite3_stmt* stmt = nullptr; sqlite3* db; char* ErrorMsg = 0; // 显式指定UTF-8编码打开数据库 int open_db = sqlite3_open_v2("test.db", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, "UTF-8"); ERRORsql(open_db, db); CreateTable(open_db, db, ErrorMsg); cout << "Начните ввод для информации в бд" << endl << "Для завершения работы пропишите //exit" << endl; while (true) { cout << "Имя: " << endl << "> "; getline(wcin, name); if (name == L"//exit") break; cout << "Возраст (по желанию или же -)" << endl << "> "; cin >> age; // 清理输入缓冲区的换行符 cin.ignore(numeric_limits<streamsize>::max(), '\n'); SetDB(db, name, age, &stmt); } cout << "До скорых встреч" << endl; sqlite3_close(db); return 0; }
关键修改说明
- 修复了
wcin和cin混用导致的输入缓冲区问题,确保能正确读取俄文姓名。 - 显式指定SQLite数据库使用UTF-8编码,避免编码不匹配。
- 将宽字符
wstring转换为UTF-8字符串后绑定,解决sqlite3_bind_text16的兼容性问题。 - 补充了原代码中缺失的颜色宏和
ERRORsql函数,确保代码可直接编译运行。
内容的提问来源于stack exchange,提问作者Григорий Жидков
相关产品推荐
相关产品推荐

