win32 读写UTF-8格式的文件的方法

news2025/7/27 20:57:59

1,写入数据

最开始是在写入数据前先写入三个字节

BYTE btHead[] = { 0xEF,0xBB,0xBF };
::WriteFile(hFile, btHead, 3, &dwWrite, 0);
::WriteFile(hFile, str, lstrlen(str)*sizeof(TCHAR), &dwWrite, 0);

这样写入后文件样式为:
在这里插入图片描述
格式是UTF-8,但后面有个BOM,而且汉字也是乱码,
最后我又测试了下用c语言写入UTF-8数据,

//打开文件,按指定编码格式打开
FILE* fp=fopen("UTF_8Test.txt", "wt+,ccs=UTF-8");

//写入数据
TCHAR str[] = TEXT("测试文件,1234,abcd,ABCD");
fwrite(str, sizeof(TCHAR), lstrlen(str), fp);

//关闭
fclose(fp);

汉字不是乱码了,但是格式仍然是UTF-8 BOM

这就是不我想要的效果。

最后查找一翻资料后,
1。先把要保存的字符串转化为UTF-8格式的char字符串
2。在写入char字符串到文件中

//lpBuffer是传来的宽字符串的指针
//nBufferLeng是字符串的字符个数(用lstrlen求出的长度)

//求字符串转为UTF-8的字符长度
int size = ::WideCharToMultiByte(CP_UTF8, 0, (LPTSTR)lpBuffer, nBufferLeng, NULL, 0, NULL,
	NULL);
	
//再转为char字符串
char* pTem = new char[size+1];
memset(pTem, 0, size);
::WideCharToMultiByte(CP_UTF8, 0, (LPTSTR)lpBuffer, nBufferLeng, pTem, size, nullptr, nullptr);
pTem[size] = '\0';

//最后写入char字符串
bResult = ::WriteFile(m_hFile, pTem, size, &dwWrite, 0);
delete[] pTem;

这样写入文件的效果:

在这里插入图片描述
这样汉字就不会出现乱码了,格式也是UTF-8,没有后面的BOM了

2。读取数据

数据的读取和写入一样,先读取数据到char数组中,再转为UTF-8格式的宽字符串中

//获得文件字节长度
int n = GetFileSize();

//写入char数组中
char* pChar = new char[n+1];
bResult = ::ReadFile(m_hFile, pChar, n, &dwRead, 0);
pChar[n] = '\0';

//计算字符串转UTF-8的字符长度
int len = MultiByteToWideChar(CP_UTF8, 0, pChar, strlen(pChar), nullptr, 0);

//转为TCHAR字符数组
TCHAR* pWChar = new TCHAR[len+1];
memset(pWChar, 0, len);
MultiByteToWideChar(CP_UTF8, 0, pChar, strlen(pChar), pWChar, len);
pWChar[len] = '\0';

//拷贝到函数外面的字符指针
lstrcpy((LPTSTR)lpBuffer, pWChar);

//清除内存
delete[] pWChar;
delete[] pChar;

读取数据的效果:
在这里插入图片描述

4。完整代码片段

QFile.h文件

//文件操作类
// 对Ascii,Unicode,UTF_8,Binary
// 四种文件格式的读写
class QFile
{
public:
	QFile();
	~QFile();
public:
	enum OpenModule	//文件打开模式
	{
		Read = GENERIC_READ,	//只读模式
		Write = GENERIC_WRITE,	//只写模式
		WriteRead = GENERIC_WRITE | GENERIC_READ //读写模式
	};

	enum FileEncoded //文件编码
	{
		enAnsii=0,	//Ansi编码
		enUnicode,	//Unicode编码
		enUTF_8,	//UTF——8编码
		enBinary	//二进制编码
	};

public:
	//以指定模式打开文件
	BOOL Open(const TCHAR* pFileName, OpenModule openModule);
	void Close();
	BOOL FileExists(const TCHAR* pFileName);//检查文件是否存在
	BOOL CreateNewFile(const TCHAR* pFileName); //创建新文件
	//以指定编码格式写入数据
	int WriteFile(void* lpBuffer, int nBufferLeng, FileEncoded encodedType);
	//以指定编码格式读取数据
	int ReadFile(void* lpBuffer, int nBufferLeng, FileEncoded encodedType);
	//获得文件的字节长度
	int GetFileSize()const;
public:
	HANDLE m_hFile;
};

QFile.cpp文件

//写入数据
int QFile::WriteFile(void* lpBuffer, int nBufferLeng, FileEncoded encodedType)
{
	if (lpBuffer == nullptr)
		return -1;

	if (m_hFile == INVALID_HANDLE_VALUE)
		return -1;

	DWORD dwWrite = 0;
	BOOL bResult = FALSE;

	//编码UTF-8的写入
	if (encodedType == enUTF_8)
	{
		int size = ::WideCharToMultiByte(CP_UTF8, 0, (LPTSTR)lpBuffer, nBufferLeng, NULL, 0, NULL,
			NULL);
		char* pTem = new char[size];
		memset(pTem, 0, size);
		::WideCharToMultiByte(CP_UTF8, 0, (LPTSTR)lpBuffer, nBufferLeng, pTem, size, nullptr, nullptr);
		pTem[size] = '\0';
		bResult = ::WriteFile(m_hFile, pTem, size, &dwWrite, 0);
		return bResult ? dwWrite : -1;
	}
	

	//Unicode编码先写入两个字节,再写入数据
	if (encodedType == enUnicode)
	{
		BYTE btHead[] = { 0xFF,0xFE };
		bResult = ::WriteFile(m_hFile, btHead, 2, &dwWrite, 0);
	}

	//其他的都是直接写入数据
	bResult = ::WriteFile(m_hFile, lpBuffer, nBufferLeng, &dwWrite, 0);

	return bResult ? dwWrite : -1;
}

//读取数据
int QFile::ReadFile(void* lpBuffer, int nBufferLeng, FileEncoded encodedType)
{
	if (lpBuffer == nullptr)
		return -1;

	if (m_hFile == INVALID_HANDLE_VALUE)
		return -1;

	DWORD dwRead = 0;
	BOOL bResult = FALSE;

	//编码格式UTF-8的读取
	if (encodedType == enUTF_8)
	{
		char* pChar = new char[nBufferLeng +1];
		bResult = ::ReadFile(m_hFile, pChar, nBufferLeng, &dwRead, 0);
		pChar[nBufferLeng] = '\0';

		int len = MultiByteToWideChar(CP_UTF8, 0, pChar, strlen(pChar), nullptr, 0);

		TCHAR* pWChar = new TCHAR[len+1];
		memset(pWChar, 0, len);
		MultiByteToWideChar(CP_UTF8, 0, pChar, strlen(pChar), pWChar, len);
		pWChar[len] = '\0';

		lstrcpy((LPTSTR)lpBuffer, pWChar);
		delete[] pWChar;
		delete[] pChar;

		return bResult ? dwRead : -1;
	}

	//编码Unicode,先跳过前两个字节再读取数据
	if (encodedType == enUnicode)
	{
		SetFilePointer(m_hFile, 2, 0, FILE_BEGIN);
	}
	bResult = ::ReadFile(m_hFile, lpBuffer, nBufferLeng, &dwRead, 0);
	
	return bResult ? dwRead : -1;
}

//…………

5。使用

//1.写入数据
QFile f;
f.Open(Utf_8Txt, QFile::Write);

TCHAR str[] = TEXT("测试数据,1234,ABCD");
f.WriteFile(str, lstrlen(str), QFile::enUTF_8);

f.Close();

//2.读取数据
QFile f;
f.Open(Utf_8Txt, QFile::Read);

TCHAR str[20] = { 0 };
int nLeng = f.GetFileSize();

f.ReadFile(str, nLeng, QFile::enUTF_8);

f.Close();

MessageBox(nullptr, str, TEXT("数据的读取"), 0);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1156697.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Python制作一个动物识别小程序

目录 引言研究背景目的与意义 动物识别技术概述基本原理图像处理与特征提取机器学习与深度学习方法 数据集与数据预处理数据收集与构建数据预处理步骤数据增强技术 特征提取与选择基础特征提取方法特征选择与降维 引言 研究背景 动物识别是计算机视觉和模式识别领域的重要研究…

《深入浅出OCR》实战:基于CRNN的文字识别

✨专栏介绍: 经过几个月的精心筹备,本作者推出全新系列《深入浅出OCR》专栏,对标最全OCR教程,具体章节如导图所示,将分别从OCR技术发展、方向、概念、算法、论文、数据集等各种角度展开详细介绍。 💙个人主页: GoAI |💚 公众号: GoAI的学习小屋 | 💛交流群: 7049325…

在python中加载tensorflow-probability模块和numpy模块

目录 操作步骤: 注意: 问题: 解决办法: 操作步骤: 在虚拟环境的文件夹中,找到Scripts文件夹,点击进去,找到地址栏,在地址栏中输入cmd,进入如下界面。 输…

国产数据库兼容过程中涉及的MySQL非严格模式

点击上方蓝字关注我 在国产数据库兼容适配过程中,经常遇到因源数据库是MySQL,迁移至其他国产数据库后,因MySQL端兼容模式有非严格模式,导致适配过程过程中需要做调整。那么,MySQL主要的非严格模式小结如下:…

约会杭州云栖2023:为了无法计算的价值一起努力

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师…

C++初阶 类和对象(上)

前言:C初阶系列,每一期博主都会使用简单朴素的语言将对应的知识分享给大家,争取让所有人都可以听懂,C初阶系列会持续更新,上学期间将不定时更新,但总会更的 目录 一、什么是面向对象编程 二、什么是类和如…

AST反混淆实战|变种ob混淆还原指南一

关注它,不迷路。 本文章中所有内容仅供学习交流,不可用于任何商业用途和非法用途,否则后果自负,如有侵权,请联系作者立即删除! 1.需求 ob混淆是我们最常见的混淆代码,标准的混淆 可以用星…

如何读懂深度学习python项目,以`Multi-label learning from single positive label`为例

Paper : Multi-label learning from single positive label Code 先读一读README.md 可能有意想不到的收获; 实验环境设置要仔细看哦! 读论文 如何读论文,Readpaper经典十问 (可能在我博客里有写) How to read a …

【UE5】如何在UE5.1中创建级联粒子系统

1. 可以先新建一个actor蓝图,然后在该蓝图中添加一个“Cascade Particle System Component” 2. 在右侧的细节面板中,点击“模板”一项中的下拉框,然后点击“Cascade粒子系统(旧版)” 然后就可以选择在哪个路径下创建级…

Notepad++下载、使用

下载 https://notepad-plus-plus.org/downloads/ 安装 双击安装 选择安装路径 使用 在文件夹中搜索 文件类型可以根据需要设置 如 *.* 说明是所有文件类型; *.tar 说明是所有文件后缀是是tar的文件‘;

【Rust日报】2023-10-30 理解 Rust 中的生命周期

理解 Rust 中的生命周期 生命周期(Lifetime)是让 Rust 成为 Rust 的关键因素。 没有了生命周期,轻松的并发、直接的内存分配和整体的数据安全都是不可能的。 但是,生命周期也很难理解,这篇教程会帮助人们理解生命周期的…

【强化学习】13 —— Actor-Critic 算法

文章目录 REINFORCE 存在的问题Actor-CriticA2C: Advantageous Actor-Critic代码实践结果 参考 REINFORCE 存在的问题 基于片段式数据的任务 通常情况下,任务需要有终止状态,REINFORCE才能直接计算累计折扣奖励 低数据利用效率 实际中&#…

【Java】多线程案例(单例模式,阻塞队列,定时器,线程池)

❤️ Author: 老九 ☕️ 个人博客:老九的CSDN博客 🙏 个人名言:不可控之事 乐观面对 😍 系列专栏: 文章目录 实现安全版本的单例模式饿汉模式类和对象的概念类对象类的静态成员与实例成员 懒汉模式如何保证…

C++设计模式_21_Iterator 迭代器(理解;面向对象的迭代器已过时;C++中使用泛型编程的方式实现)

Iterator 迭代器也是属于“数据结构”模式。GoF中面向对象的迭代器已经过时,C中目前使用泛型编程的方式实现,其他语言还在使用面向对象的迭代器。 文章目录 1. 动机(Motivation)2. 模式定义3. Iterator 迭代器代码分析4. 面向对象的迭代器与泛型编程实现…

一天写一个(前端、后端、全栈)个人简历项目(附详源码)

一、项目简介 此项目是用前端技术HTMLCSSjquery写的一个简单的个人简历项目模板,图片可点击放大查看,还可以直接下载你的word或者PDF的简历模板。 如果有需要的同学可以直接拿去使用,需自行填写个人的详细信息,发布,…

uniapp 开发微信小程序 v-bind给子组件传递函数,该函数中的this不是父组件的二是子组件的this

解决办法:子组件通过缓存子组件this然后,用bind改写this 这个方法因为定义了全局变量that 那么该变量就只能用一次,不然会有赋值覆盖的情况。 要么就弃用v-bind传入函数,改为emit传入自定义事件 [uniapp] uview(1.x) 二次封装u-navbar 导致…

程序开发设计原则

(图片来自网络) 单一职责 Single Responsibility Principle 不论是在设计类,接口还是方法,单一职责都会处处体现,单一职责的定义:我们把职责定义为系统变化的原因。所有在定 义类,接口&#xff…

CV2 将图片中某个点与中心点的角度变换成0-360度

众所周知,CV2中的坐标方向是这样的: 所以一般我们想计算图片中某个点P1(x1,y1)与中心点P0(x0,y0)的方向时,我们会先将y坐标翻上去,然后计算角度。即: p1_xint(x1) # p1_yint(y1)p0_xint(x0) #图像大小为512*512中心点坐标为25…

PO-提示json不能为空 not valid json at character 2 of ““““

问题描述: 调用第三方REST接口,提示提示json不能为空 not valid json at character 2 of """" 原因分析: 一般都是对方接收后出现错误没有处理,返回空值;有可能是他们映射有问题 解决方案&…

小程序获取头像和昵称的思路

小程序获取头像和昵称的基本方法是调用小程序自带的API wx.getUserProfile(),这也是小程序官方目前最推荐的做法。成功获取用户名头像之后,小程序允许保存调用的结果,以便下一次打开页面的时候自动显示头像和名字。保存用户名和头像并不是保存…