编程环境全部设置为utf8
h、cpp文件全部以utf8 unicode(utf8带签名,代码页65001)格式保存。
qt5以上程序在main函数中设置:
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
配置文件、xml文件等都采用utf8格式存储。
数据库、网络数据,均采用utf8编码。
底层代码封装utf8到local的转换
win7默认字符集是local。gb2312之类的。
win10默认字符集似乎也不是utf8。
那么,当底层读写文件时,发现读写失败,可以继续执行以下代码:
1、判断file_name是否为utf8字符集,如果是,转化为本地字符集继续读写。
2、如果不是utf8字符集,那就直接报错退出。
对于上层代码的编写人员来说,不需要关心文件名的转码问题(但是要求全部环境都默认utf8)。
以下是示例代码,用pugixml开源库读写xml文件,底层封装编码问题后,上层就省事了。
pugi::xml_document xml_doc;
pugi::xml_parse_result result = xml_doc.load_file(file_name.c_str());
int flag = result.status;
if (flag != pugi::status_ok)
{
if (isUtf8Str(file_name))
{
const std::string local_file_name = CodePageInfor::Utf8ToLocal(file_name);
result = xml_doc.load_file(local_file_name.c_str());
flag = result.status;
}
}
if (flag == pugi::status_ok){
...
}
else{
...
}
pugi::xml_document save_xml_doc;
pugi::xml_node node = save_xml_doc.prepend_child(pugi::node_declaration);
node.append_attribute("version") = "1.0";
node.append_attribute("encoding") = encoding.c_str();
pugi::xml_node root = save_xml_doc.append_child(p_root_ref->tag_name().c_str());
int flag = write_to_xml(root, p_root_ref);
if (flag != pugi::status_ok)
{
show_pugi_error(flag, file_name);
}
bool b = save_xml_doc.save_file(file_name.c_str(), PUGIXML_TEXT("\t"));
if (!b)
{
if (isUtf8Str(file_name))
{
const std::string local_file_name = CodePageInfor::Utf8ToLocal(file_name);
b = save_xml_doc.save_file(local_file_name.c_str(), PUGIXML_TEXT("\t"));
}
if (!b)
{
GuiLogFL(std::string("pugi::xml_document.save_file(...) error:") + file_name);
}
}
iconv库及cpp接口封装:
https://download.csdn.net/download/weixin_43172531/12073477
CodePageInfor类的定义:
https://blog.csdn.net/weixin_43172531/article/details/103424465
isUtf8Str的定义:
https://blog.csdn.net/weixin_43172531/article/details/103800672
今天遇到一个特殊问题,目录中仅仅含有“转”一个中文字,导致代码判断utf8存在问题,进而转换也存在问题。解决方案是:用系统判断文件是否可以访问的函数来识别字符串转换是否正确,例如access函数。转换不正确就尝试多种转换。
std::string StdBaseApi::ToExistFileName(const std::string &str)
{
//initemplatepath = QString::fromLocal8Bit(StdBaseApi::ToExistFileName(initemplatepath.toStdString()).c_str()); //外部使用QString时的例子
if (str.length() == 0)
{
return str;
}
if (IsFileExist(str))
{
return str;
}
std::string str_temp = ToLocal(str);
if (IsFileExist(str_temp))
{
return str_temp;
}
str_temp = ToUtf8(str);
if (IsFileExist(str_temp))
{
return str_temp;
}
str_temp = ToLocal(str, true);
if (IsFileExist(str_temp))
{
return str_temp;
}
str_temp = ToUtf8(str, true);
if (IsFileExist(str_temp))
{
return str_temp;
}
return "";
}
bool StdBaseApi::IsFileExist(const std::string &file_name)
{
return (access(file_name.c_str(), 0) == 0);
}
bool StdBaseApi::IsFolderExist(const std::string &file_name)
{
// unistd.h
//#define F_OK 0 是否存在
//#define R_OK 4 是否有读权限
//#define W_OK 2 是否有写权限
//#define X_OK 1 是否有执行权限
//如果指定的方式有效,则此函数返回0,否则返回-1
return (access(file_name.c_str(), 0) == 0);
}
std::string StdBaseApi::ToUtf8(const std::string &str, const bool bForce/* = false*/)
{
if (str.length() == 0)
{
return str;
}
return CodePageInfor::LocalToUtf8(str, bForce);//内部识别utf8、非utf8
}
std::string StdBaseApi::ToLocal(const std::string &str, const bool bForce/* = false*/)
{
if (str.length() == 0)
{
return str;
}
return CodePageInfor::Utf8ToLocal(str, bForce);//内部识别utf8、非utf8
}
static bool isUtf8Str(const std::string &str)
{
return isUtf8Str(str.c_str());
}
static std::string LocalToUtf8(const std::string &str, const bool bForce = false)
{
if (!bForce) //20210930 非强制转换时增加判断
{
if (isUtf8Str(str))
{
return str;//20210715 已经是utf8时,直接返回。
}
}
std::string cur_name = CodePageInfor::GetCurrentCodePageName();
if (cur_name.length() == 0)
{
return "";
}
iconv_t cd = iconv_open("utf-8", cur_name.c_str());
if (cd == 0)
{
return "";
}
const char *inbuftt = str.c_str();
const char *inbuf = inbuftt;
size_t inlen = strlen(inbuf);
if (inlen == 0)
{
iconv_close(cd);
return "";
}
size_t outlen = inlen * 6;
char *outbuf = new char[outlen];//长度改成动态长度,考虑inlen乘以6
if (outbuf == NULL)
{
iconv_close(cd);
return "";
}
memset(outbuf, 0, outlen);
char *outbuftt = outbuf;
int iconv_ret = iconv(cd, &inbuf, &inlen, &outbuftt, &outlen);
if (iconv_ret == -1)
{
iconv_close(cd);
if (outbuf)
{
delete[] outbuf;
}
return "";
}
else
{
std::string str_ret(outbuf);
iconv_close(cd);
if (outbuf)
{
delete[] outbuf;
}
return str_ret;
}
}
static std::string Utf8ToLocal(const std::string &str, const bool bForce = false)
{
if (!bForce) //20210930 非强制转换时增加判断
{
if (isUtf8Str(str) == false)
{
return str;//20210715 已经不是utf8时,直接返回。
}
}
std::string cur_name = CodePageInfor::GetCurrentCodePageName();
if (cur_name.length() == 0)
{
return "";
}
iconv_t cd = iconv_open(cur_name.c_str(), "utf-8");
if (cd == 0)
{
return "";
}
const char *inbuftt = str.c_str();
//const char *inbuftt = "D:/sf_svn/aesp/atest/0608主子机测试/b1/1000K/j1/d1/cpu_config/sdc/DEMO_SDC(CPU)_V1.000.000.000_170713_73635A48.sdc"; //utf8
const char *inbuf = inbuftt;
size_t inlen = strlen(inbuf);
if (inlen == 0)
{
iconv_close(cd);
return "";
}
size_t outlen = inlen * 6;
char *outbuf = new char[outlen];//长度改成动态长度,考虑inlen乘以6
if (outbuf == NULL)
{
iconv_close(cd);
return "";
}
memset(outbuf, 0, outlen);
iconv(cd, NULL, NULL, NULL, NULL);
char *outbuftt = outbuf;
int iconv_ret = iconv(cd, &inbuf, &inlen, &outbuftt, &outlen);
if (iconv_ret == -1)
{
iconv_close(cd);
if (outbuf)
{
delete[] outbuf;
}
return "";
}
else
{
std::string str_ret(outbuf);
iconv_close(cd);
if (outbuf)
{
delete[] outbuf;
}
return str_ret;
}
}