读写中文路径下文件的通用方案

21 篇文章 0 订阅

编程环境全部设置为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;
        }
	}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值