一、背景
用VS做Qt开发,源码文件默认是GBK编码。但做跨平台,同样的源码复制到麒麟的QtCreator,必须手动选择GB2312编码才能修改代码。
另外,Windows的Sourcetree默认是UTF8,所以GBK编码的源码显示乱码。
想统一用UTF8,但原工程是VS开发的,大量的源码需要改为UTF8,于是写了一段代码做转换。
下面将文件统一处理为带BOM的UTF8编码。
二、转码实现
转码前必须对文件进行识别,已经是UTF8编码了就不能再转UTF8,不然又乱了。
1、定义文件类型
typedef enum {
UTF8_Unknown,
UTF8_NOT,
UTF8_BOM,
UTF8_NOBOM
}UTF8Status;
定义了四种:未知文件不做处理;非UTF8则转为带BOM的UTF8编码;带BOM的UTF8不做处理;不带BOM的UTF8则加上BOM。
2、识别文件类型
UTF8Status file_is_utf8(QFile &file)
{
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
bool firstIsBOM = false;
UTF8Status result = UTF8Status::UTF8_NOBOM;
QByteArray contentBytes = file.readAll();
for (int i = 0; i < contentBytes.size();)
{
uchar ch = contentBytes.at(i);
// ASCII字符
if (ch < 0x80)
{
i++;
continue;
}
// 无效的UTF8字符
else if (ch < 0xC0)
{
result = UTF8Status::UTF8_NOT;
break;
}
// 2字节的UTF8字符
else if (ch < 0xE0)
{
if (i >= contentBytes.size() - 1)
{
result = UTF8Status::UTF8_Unknown;
break;
}
if ((contentBytes.at(i + 1) & 0xC0) != 0x80)
{
result = UTF8Status::UTF8_NOT;
break;
}
i += 2;
}
// 3字节UTF8字符
else if (ch < 0xF0)
{
if (i >= contentBytes.size() - 2)
{
result = UTF8Status::UTF8_Unknown;
break;
}
if ((contentBytes.at(i + 1) & 0xC0) != 0x80 || (contentBytes.at(i + 2) & 0xC0) != 0x80)
{
result = UTF8Status::UTF8_NOT;
break;
}
// 是否为BOM
if (i == 0)
{
uchar ch1 = contentBytes.at(i + 1);
uchar ch2 = contentBytes.at(i + 2);
if (ch == 0xEF && ch1 == 0xBB && ch2 == 0xBF)
{
firstIsBOM = true;
}
}
i += 3;
}
// 非法
else
{
result = UTF8Status::UTF8_NOT;
break;
}
}
file.close();
if (UTF8Status::UTF8_Unknown == result || UTF8Status::UTF8_NOT == result)
{
return result;
}
return firstIsBOM ? UTF8Status::UTF8_BOM : UTF8Status::UTF8_NOBOM;
}
return UTF8Status::UTF8_Unknown;
}
3、对具体的文件进行编码转换
void convert_file(QString filepath)
{
UTF8Status result = file_is_utf8(QFile(filepath));
if (UTF8Status::UTF8_Unknown == result || UTF8Status::UTF8_BOM == result)
{
return;
}
QString contentString;
QFile file(filepath);
// 以GBK编码读出
if (result == UTF8Status::UTF8_NOT)
{
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QTextStream stream(&file);
stream.setCodec("gbk");
contentString = stream.readAll();
file.close();
}
}
// 以UTF8编码读出
else
{
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QTextStream stream(&file);
stream.setCodec("utf8");
contentString = stream.readAll();
file.close();
}
}
// 以UTF8编码写入
if (file.open(QIODevice::WriteOnly | QIODevice::Text))
{
QByteArray contentBytes = contentString.toUtf8();
// 前三个字节是BOM
char bom[3];
bom[0] = 0xEF;
bom[1] = 0xBB;
bom[2] = 0xBF;
contentBytes = contentBytes.insert(0, bom, 3);
// 写入文件
file.write(contentBytes);
file.close();
}
}
4、对文件或文件夹进行编码转换
void gbk_utf8(QString path)
{
// 是文件则直接转码
QFileInfo fileInfo(path);
if (fileInfo.isFile())
{
// 转码
convert_file(path);
return;
}
// 是文件夹,则遍历该文件夹
QStack<QString> stack;
stack.push_back(path);
while (stack.size() > 0)
{
QString path = stack.pop();
// 遍历文件夹下的所有文件夹和文件
QDir dir(path);
QFileInfoList fileInfoList = dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
for each (QFileInfo fileInfo in fileInfoList)
{
// 是文件则转码
if (fileInfo.isFile())
{
// 只处理h文件和cpp文件
QString suffix = fileInfo.suffix();
if (suffix.length() > 0 && (suffix.compare("h") == 0 || suffix.compare("cpp") == 0))
{
// 转码
convert_file(fileInfo.absoluteFilePath());
}
continue;
}
// 是文件夹,则继续遍历
stack.push(fileInfo.absoluteFilePath());
}
}
}
如果输入参数是文件路径,则对该文件进行编码转换;如果输入参数是文件夹路径,则对该文件夹下所有h文件和cpp文件进行编码转换。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)