用Qt实现文件转码

2023-05-16

一、背景

用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(使用前将#替换为@)

用Qt实现文件转码 的相关文章

随机推荐

  • 基于Jeecg使用vue-konva

    konva是一个基于canvas的可视化框架 xff08 https konvajs org xff09 xff0c vue konva则是基于vue的 当前的一个小项目是基于Jeecg开发的 xff0c 想做可视化的功能 xff0c 于是
  • 基于JeecgBoot的v-has权限控制

    v has是一个很方便的前端权限控制标签 xff0c 但是只支持一个授权标识 xff0c 如果需要两个或以上的权限与或运算就不支持了 解决方案 xff1a 修改文件 64 utils hasPermission js 中的方法filterG
  • 前后端离线开发相关软件下载地址大全

    一 后端开发 xff1a 1 IDEA Windows xff1a https www jetbrains com zh cn idea download section 61 windows 2 JDK Windows xff1a htt
  • 离线部署GitLab

    一 背景 公司是局域网开发环境 xff0c 资源文件用svn管理 xff0c 代码用git管理 GitLab有点大 xff0c 而且只能在Linux下使用 xff0c 所以选择了轻巧的GitBlit 后来GitBlit被暴漏洞 xff0c
  • C# WPF实战项目升级了

    概述 之前用Caliburn Micro搭建的WPF实战项目 xff0c CM框架选用了 3 0 3 xff0c 实际上CM框架目前最新版已经到4 0 173了 xff0c 所有很有必须升级一下项目了 本来打算把平台框架也直接升级到 NET
  • 接入Swagger2(1) —— SwaggerUI

    关于Swagger不再多述 xff0c 这里只分享接入方式 1 接入 SpringBoot中引入Swagger相当简单 xff0c 只需要添加一个依赖就行 xff0c 如下 xff1a lt dependency gt lt groupId
  • 接入Swagger2(2) —— knife4j

    上一篇文章介绍了Swagger2默认UI的接入方式 xff0c 但是UI实在太丑 xff0c 而且布局也很难用 xff0c 这里介绍一个相对漂亮点的UI knife4j knife4j是基于swagger2开发的 xff0c 是swagge
  • SpringSecurity的使用(1)—— 起步

    年初就关注到SpringSecurity了 xff0c 看官网 xff0c 看不懂 xff1b 查资料 xff0c 跟我预想的不一样 xff0c 所以一直入不了门 有博文说添加依赖 xff0c 再次启动项目就会跳转到登录页面 我是前后端分离
  • 离线模式:Unresolved dependency: ‘com.xx.xx:xx-xx:jar:x.x.x‘

    SpringBoot最常用的编译器就是IDEA xff0c 如果不能联网 xff0c 则需要将工程设置为离线模式 1 遇到的问题 这两天遇到了这样的问题 xff1a JeecgBoot的工程中有添加依赖包 knifej spring boo
  • SpringBoot中Java调用dll

    1 背景 最近接手的项目 xff0c 底层算法是C 43 43 写的 xff0c 并且封装成了dll 而目前的需求 xff0c 需要把这些算法移到服务端执行 不可能把C 43 43 写的算法库改用Java重写一遍 xff0c 而且也基于执行
  • 接入Shiro(1)——极简登录认证

    Shiro是一个强大易用的Java安全框架 xff0c 提供了认证 授权 加密和会话管理等功能 之前的开发都是在低代码上直接使用Shiro xff0c 一般也不需要修改 在SpringBoot的基础上 xff0c 只接入Shiro的登录认证
  • 接入Shiro(2)——基于JWT的登录认证

    前文讲到基于Shiro的登录认证 xff0c 只是对前端传来的token长度做了判断 xff0c 并没有与用户关联 本文将分享用户登录 Token创建 Token验证三个关键环节的用法 xff0c 其中用户登录只对用户名和密码做简单的比对
  • VS2017离线安装

    因开发环境限制 xff0c 不联外网开发是一种很常见的情况 xff0c 但官方似乎不提供vs2017离线安装包 几经周折 xff0c 终于找到了解决办法 1 vs2017下载地址 Visual Stduio 旧版本下载地址 Visual S
  • Invalid or corrupt jarfile xxx.jar

    一 遇到的问题 Artifacts打包的特点是 xff0c 目录下会生成一大堆jar包 xff0c 各个依赖包都是独立存在的 xff0c 更新时只替换开发包即可 之前一直用Artifacts打的包 xff0c 会生成MANIFEST MF文
  • GitLab的备份与还原

    一 现状 前段时间在麒麟系统上部署了GitLab xff0c 后来发现太占资源 xff0c 于是准备在Ubuntu Desktop版本上部署GitLab Ubuntu Desktop出预装了浏览器 xff0c 感觉不会比麒麟轻太多 之前安装
  • 如何使用Sublime的插件(以HexViewer为例)

    1 打开Package Control功能 xff1a 在sublime任意界面按下ctrl 43 xff08 注意是键盘左上角的 xff09 xff0c 会在界面最下方弹出一个编辑框 xff0c 输入如下内容 xff08 注意区分Subl
  • Java和Qt如何实现multipartfile表单的请求

    一 背景 做项目经常需要跟其他单位 公司对接 xff0c 由于成本等方面的考虑 xff0c 不可能多家单位一直坐在一起开发 一般的解决办法是 xff0c 自己的B端 C端先与自己的服务端对接 xff0c 基本功能开发完成 xff0c 再将自
  • 树的排布、展开与折叠算法

    一 背景 原项目是纯C端程序 xff0c 未来要移植成BS架构 其中一个功能是界面上展示树 xff0c 基本要求是 xff1a xff08 1 xff09 按层次展示树各个结点 xff08 2 xff09 根结点以及各个子树结点可以点击 x
  • 常用git命令

    一 背景 做Qt开发一直在Windows平台上 xff0c 客户要求移植到麒麟系统 Windows和麒麟共用一套代码 xff0c 所以麒麟系统上的代码也需要与Git服务器同步 好用的Sourcetree没有Linux版本 xff0c 无奈只
  • 用Qt实现文件转码

    一 背景 用VS做Qt开发 xff0c 源码文件默认是GBK编码 但做跨平台 xff0c 同样的源码复制到麒麟的QtCreator xff0c 必须手动选择GB2312编码才能修改代码 另外 xff0c Windows的Sourcetree