在业务流程中需要记录一下已经处理过的文件信息,用到了sqlite库。写库的时候先用Cstring构造sql语句,再将unicode的Cstring转换为utf8的编码,最后调用sqlited3_exec执行语句。大概代码如下:
CString insertSql;
insertSql.Format(L"insert into file_processed values('%s','%s','%s');",code,filePath,result);
int nLen = WideCharToMultiByte(CP_UTF8, 0, insertSql, -1, NULL, 0, NULL, NULL);
char *szUtf8 = new char[nLen + 1];
memset(szUtf8, 0, nLen + 1);
WideCharToMultiByte (CP_UTF8, 0, insertSql, -1, szUtf8, nLen, NULL,NULL);
delete szUtf8;
sqlite3_exec(db,szUtf8,nullptr,nullptr,nullptr);
插入时没啥问题,但是在查询的时候发现使用第二个字段做条件查询,怎么都出不来结果。比如库中内容如下:
使用
select * from file_processed where file_processed.[file_path]='D:\work\3690004\20201109\132493576403069034\6\3363\20201109001\安徽大学\17级李莹、文迪、王韵思\多小样\文迪\';
去查询,查到的记录数都是0。反复尝试之后,观察到在sqlite expert中的执行插入语句插入的记录是可以通过上述语句查询到的。遂怀疑字段内容有误,使用sqlite expert中hex edito查看字段16进制值进行对比后终于发现了问题所在。
通过程序插入的字段内容如下:
通过sqlite expert插入的字段内容如下:
注意到通过程序插入的内容在开始的地方多了三字节,即0xE280AA。百度之后找到以下信息:
您的属性文本以UTF-8编码。
e2 80 aa
是Unicode代码点U+202A LEFT-TO-RIGHT EMBEDDING
的UTF-8编码。
e2 80 ac
是Unicode代码点U+202C POP DIRECTIONAL FORMATTING
的UTF-8编码。这些标记用于在双向文本中嵌入从左到右的文本。
雷蒙德陈的博客上讲述这个关于类似的问题,在Windows资源管理器中显示的文件名:
Why is there an invisible U+202A at the start of my file name?
引用自:http://cn.voidcc.com/question/p-fempitpe-bhy.html
这是不可见的内容,所以在库里面看到的显示的内容是一样的。
找到了问题,解决办法就简单了,将查询语句改为
select * from file_processed where file_processed.[file_path] like '%D:\work\3690004\20201109\132493576403069034\6\3363\20201109001\安徽大学\17级李莹、文迪、王韵思\多小样\文迪\';
就可以正确查找对应的记录。
另一种就是在插入的时候清洗输入的内容,那个就涉及到Cstring以及WideCharToMultiByte内部的流程,一时半会儿也折腾不出来,有时间再说吧。