MFC 读写 文件 内容 包含 中文 英文 数字
CStdioFile-derived class for multibyte and Unicode reading and writing
https://www.codeproject.com/Articles/4119/CStdioFile-derived-class-for-multibyte-and-Unicode
MFC/C++ CFile写入文件数据,输出utf-8的文本。(防止中文乱码)
https://blog.csdn.net/weekdawn/article/details/73467927
需求说明:有时候用CFile写入文件的内容会出现中文乱码问题,这时候就需要把写入的文件编码类型改为utf-8的类型。
代码功能:输出utf-8格式的内容到文件中
作者:weekdawn
try
{
//创建mht文件,并写入数据
mhtFile.Open(filePath, CFile::modeCreate|CFile::modeWrite); //mhtFile为CFile类型,filePath为文件路径CString类型
//-------以下是将Unicode字符转为utf-8字符,这样才能正常显示中文
DWORD dwFileLen = mhtFile.GetLength();
if (0 == dwFileLen)
{
const unsigned char LeadBytes[] = {0xEF, 0xBB, 0xBF};
mhtFile.Write(LeadBytes,sizeof(LeadBytes));
}
int nSrcLen = (int)wcslen(content);//content为要写入的文本
CStringA utf8String(content);
int nBufLen = (nSrcLen+1) * 6;
LPSTR buffer = utf8String.GetBufferSetLength(nBufLen);
int nLen = AtlUnicodeToUTF8(content, nSrcLen, buffer, nBufLen);
//上面的函数AtlUnicodeToUTF8()需头文件:<atlenc.h>
//功能:将unicode转换成utf-8
buffer[nLen] = 0;
utf8String.ReleaseBuffer();
mhtFile.SeekToEnd();
//将转码后的内容写入mht文件
mhtFile.Write(utf8String.GetBuffer(),nLen);
mhtFile.Write("\r\n",2);
mhtFile.Close();
}
catch(CFileException *e)
{
CString errInfo;
errInfo.Format(_T("%s"),e->ReportError());
MessageBox(_T("文件创建失败!") + errInfo);
}
在MFC中用CStdioFile对象输出utf-8和ansi编码的文本
转自:http://blog.csdn.net/thinkhy/article/details/5740748
下面的代码分别输出UTF-8和ANSI(简体中文Windows上是GBK编码)两种编码的文本文件。
//
// 写UTF-8文本
// 下列文件类操作中可能抛出一个CFileException异常
try {
CStdioFile hfile( strFilePath, CFile::modeReadWrite);
if(hfile.m_hFile)
{
DWORD dwFileLen = hfile.GetLength();
if (0 == dwFileLen) // 文件为空时写入UTF字节序标记
{
const unsigned char LeadBytes[] = {0xEF, 0xBB, 0xBF};
hfile.Write(LeadBytes, sizeof(LeadBytes));
}
int nSrcLen = (int)wcslen(lpstrWord);
CStringA utf8String(lpstrWord);
int nBufLen = (nSrcLen+1) * 6;
LPSTR buffer = utf8String.GetBufferSetLength(nBufLen);
// 将UNICODE 转换成UTF8
// 需要函数AtlUnicodeToUTF8 头文件: <atlenc.h>
int nLen = AtlUnicodeToUTF8(lpstrWord, nSrcLen, buffer, nBufLen); // int nLen = utf8String.GetLength();
buffer[nLen] = 0;
utf8String.ReleaseBuffer();
//写文件
hfile.SeekToEnd();
hfile.Write((LPCSTR)utf8String, nLen);
hfile.Write("\r\n", 2);
hfile.Close();
}
}
catch(CFileException* pException)
{
CString strMsg;
TCHAR szErrorMessage[512];
if (pException->GetErrorMessage(szErrorMessage,
sizeof(szErrorMessage)/sizeof(*szErrorMessage), 0))
strMsg.Format(_T("(%s:%d)/n%s"), _T(__FILE__), __LINE__, szErrorMessage);
else
strMsg.Format(_T("(%s:%d)"), _T(__FILE__), __LINE__);
AfxMessageBox(strMsg);
}
// 写ANSI文本:
try {
CStdioFile hfile( strHeiMaiUsrLibPath, CFile::modeReadWrite);
if(hfile.m_hFile)
{
// 将Unicode字符串赋给Ansi格式的CStringA,实现Unicode=>Ansi转换
CStringA utf8String(lpstrWord);
int nLen = utf8String.GetLength();
// 写文件
hfile.SeekToEnd();
hfile.Write((LPCSTR)utf8String, nLen);
hfile.Write("\r\n", 2);
hfile.Close();
}
}
catch(CFileException* pException)
{
CString strMsg;
TCHAR szErrorMessage[512];
if (pException->GetErrorMessage(szErrorMessage, sizeof(szErrorMessage)/sizeof(*szErrorMessage), 0))
strMsg.Format(_T("(%s:%d)/n%s"), _T(__FILE__), __LINE__, szErrorMessage);
else
strMsg.Format(_T("(%s:%d)"), _T(__FILE__), __LINE__);
AfxMessageBox(strMsg);
}
VC 工程设置为 unicode 字符集和 多字节字符集 有什么区别?unicode 字符集字符集界面上的优点是啥?
GB2312 和utf-8文本的CStudioFile 读取方法
ANSI 与utf-8的读取方法
CFile 与 CStdioFile 的区别
CStdioFile在UNICODE字符集下读写中文
https://blog.csdn.net/s634772208/article/details/71437603
问题
以CFile::typeBinary的形式读写包含中文的文件,未出现乱码。
以CFile::typeText方式读写, 分两种情况:在多字节字符集下,使用CStdioFile::ReadString读取包含中文的文件,正常;工程编码切换至UNICODE字符集,则出现了中文乱码。
从以上信息中提取到关键信息:
在文本模式下,使用UNICODE版本的IO操作函数(如_wfopen,
fgetws等)时,函数会假定操作的对象是多字节序列(即文件存放的是多字节内容)。这些函数内部会做转换,比如读取时,就会将多字节序列转换成宽字节;写入时,就会将宽字节转换成多字节序列。
在二进制模式下,函数会假定操作的对象是UNICODE序列(即文件存放的是UNICODE内容,即每个字符都用二或四(极少的情况下)个字节存储在文件中,除非显式写入,否则文件中不带BOM头)
Unicode环境下用CFile对文件操作(解决读写乱码)(运行环境vs2015)
全部都是论坛上找到的代码,自己整理了一下,主要目的是方便以后自己查找使用。
判断文件是Unicode编码还是ANSI编码
int IsUnicodeFile(PTSTR pstrName)//这个函数是判断函数,()内是文件路径,如果是Unicode则该函数值是1
{
try
{
CFile file(pstrName, CFile::modeRead);
BYTE ch[100];
memset(ch, 0, 100);
int ii = file.Read(ch, 100);
file.Close();
int i = 0;
int iU = IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_REVERSE_SIGNATURE;
if (IsTextUnicode(ch, 100, &iU))//是否是unicode文件
{
return 1;
}
return 0;
}
catch (CException* e)
{
return -1;
}
return 0;
}
2.如果是Unicode文件则转化成ANSI编码文件
void CViewdataDlg::UnicodeFile2ANSIFile()//函数功能:如果是Unicode文件则把文件转换成ansi格式文件
{
if (IsUnicodeFile(_T("")) == 1)//双引号里为文件路径
{
/*********************打开文件*********************************************/
CFile file;
CFileException e;
TCHAR* pszFileName = _T("");//双引号里为文件路径
if (!file.Open(pszFileName, CFile::modeReadWrite, &e))
{
TRACE(_T("File could not be opened %d\n"), e.m_cause);
}
//MessageBox(_T("打开成功"));
/*********************读取文件*********************************************/
LONGLONG wfilelen = file.GetLength();
TCHAR *wp = new TCHAR[wfilelen + 1];
memset(wp, 0, (wfilelen + 1) * sizeof(TCHAR));
file.Seek(2, 0);
file.Read(wp, wfilelen);
wp[wfilelen] = _T('\0');
//MessageBox(wp);
file.Close();
/*********************把读取到的宽字符转成多字符*********************************************/
LONGLONG filelen = WideCharToMultiByte(CP_OEMCP, NULL, wp, -1, NULL, 0, NULL, FALSE);
char *p = new char[filelen];
if (!p){delete[] p;}
WideCharToMultiByte(CP_OEMCP, NULL, wp, -1, p, filelen, NULL, FALSE);
/*********************写入成ansi文件*********************************************/
if (!file.Open(pszFileName, CFile::modeCreate | CFile::modeWrite, &e))
{TRACE(_T("File could not be opened %d\n"), e.m_cause);}
file.Write(p, filelen - 1);
delete[] wp;
delete[] p;
file.Close();
}
else{}
}
3.读取ansi编码文件
/*********************打开文件***********************************************************/
CFile file;
CFileException e;
TCHAR* pszFileName = _T("");//双引号内为文件路径
if (!file.Open(pszFileName, CFile::modeReadWrite, &e))
{
TRACE(_T("File could not be opened %d\n"), e.m_cause);
}
MessageBox(_T("打开成功"));
/*********************读取文件**********************************************************/
LONGLONG ansifilelen = file.GetLength();//获得ansi编码文件的文件长度
char *p = new char[ansifilelen + 1];//new一块新内存
file.Read(p, ansifilelen);
p[ansifilelen] = '\0';
LONGLONG unicodefilelen = MultiByteToWideChar(CP_ACP, 0, p, strlen(p), NULL, 0);//把ansi文件长度转为Unicode文件长度
wchar_t *wp = new wchar_t[unicodefilelen + 1];//new一块新内存
MultiByteToWideChar(CP_ACP, 0, p, strlen(p), wp, unicodefilelen);//把读到的文件转成宽字符
wp[unicodefilelen] = '\0';
delete[] p;//释放内存
//MessageBox(wp);
file.Close();
//delete[] wp;//在用完之后释放内存
4.获取文件一共有多少行
char a[1];
int nline = 0;
if (!file.Open(pszFileName, CFile::modeReadWrite, &e))
{
TRACE(_T("File could not be opened %d\n"), e.m_cause);
}
while (file.Read(a, 1) != 0)
{
if (a[0] == '\n')
nline++;
}
nline += 1;
CString line;
line.Format(_T("文件行数为:%d"), nline);
MessageBox(line);
file.Close();
5.把ANSI文件转成Unicode文件
void CViewdataDlg::ANSIFile2UnicodeFile()
{
/*********************打开文件******************************************************************/
CFile file;
CFileException e;
TCHAR* pszFileName = _T("");
if (!file.Open(pszFileName, CFile::modeRead, &e))
{
TRACE(_T("File could not be opened %d\n"), e.m_cause);
}
/*********************读取文件******************************************************************/
LONGLONG ansifilelen = file.GetLength();//获得ansi编码文件的文件长度
char *p = new char[ansifilelen + 1];//new一块新内存
file.Read(p, ansifilelen);
p[ansifilelen] = '\0';
LONGLONG unicodefilelen = MultiByteToWideChar(CP_ACP, 0, p, strlen(p), NULL, 0);//把ansi文件长度转为Unicode文件长度
wchar_t *wp = new wchar_t[unicodefilelen + 1];//new一块新内存
MultiByteToWideChar(CP_ACP, 0, p, strlen(p), wp, unicodefilelen);//把读到的文件转成宽字符
wp[unicodefilelen] = '\0';
delete[] p;//释放内存
file.Close();
/*********************写入成Unicode文件*******************************************************/
CFile wfile;
CFileException we;
if (!wfile.Open(_T(""), CFile::modeCreate | CFile::modeWrite, &we))
{
TRACE(_T("File could not be opened %d\n"), we.m_cause);
}
wchar_t unicode = 0xFEFF; //这句重要
wfile.Write(&unicode, sizeof(wchar_t)); //这句重要
wfile.Write(wp, unicodefilelen * 2);
// MessageBox(wp);
delete[] wp;
wfile.Close();
}
通过资源管理器选择一个文件,并文件有多少行
void CFileTestDlg::OnBnClickedSelectfileBtn()
{
// TODO: 在此添加控件通知处理程序代码
//TCHAR szFilters[] = _T("文本文件 (*.txt)|*.txt|All Files (*.*)|*.*||");
TCHAR szFilters[] = _T("文本文件 (*.dat)|*.dat|");
CFileDialog fileDlg(TRUE, _T("dat"), _T("*.dat"),
OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, szFilters);
CString pathName;
if (fileDlg.DoModal() == IDOK)
{
pathName = fileDlg.GetPathName();
SetDlgItemText(IDC_SELECTFILE_EDIT, pathName);
//CString fileName = fileDlg.GetFileTitle();
//SetWindowText(fileName);
}
CStdioFile file;
file.Open(pathName, CStdioFile::modeRead, 0);
int nRow = 0;
TCHAR buf[1024];
while (file.ReadString(buf, 1023))
{
nRow++;
}
file.Close();
CString str_nRow;
str_nRow.Format(_T("文件有%d行"), nRow);
MessageBox(str_nRow);
}
VC++2015 CFile操作文件写入文字解决乱码
检查字符集是否Unicode.
再参考示范代码:
void CCFile_testDlg::OnBnClickedBtnFwrite()
{
// TODO: 在此添加控件通知处理程序代码
char szCurrentDateTime[32];
char szCurrentDateTime1[32];
char path1[32] = {"d:\\txw\\"};
CString path2,path5;
CTime nowtime;
nowtime = CTime::GetCurrentTime();
sprintf_s(szCurrentDateTime, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
nowtime.GetYear(), nowtime.GetMonth(), nowtime.GetDay(),
nowtime.GetHour(), nowtime.GetMinute(), nowtime.GetSecond());
sprintf_s(szCurrentDateTime1, "%.4d-%.2d-%.2d",
nowtime.GetYear(), nowtime.GetMonth(), nowtime.GetDay());
//path2.Format(_T("%s"), szCurrentDateTime1);
strcat_s(path1, szCurrentDateTime1);
strcat_s(path1, ".txt");
path2.Format(_T("%s"), path1);
CString douhao = _T(",");
CString hanzi = _T("自然");
CString strEnter = _T("\r\n");//换行
path5 = szCurrentDateTime; //日期时间
//AfxMessageBox(path2);
CFile file_1;
file_1.Open(_T("d://txw//tt19.csv"), CFile::modeNoTruncate | CFile::modeCreate | CFile::modeWrite);//打开文件
file_1.SeekToEnd();//数据位置跳到文件末端
//WORD unicode = 0xFEFF; //这句重要
wchar_t unicode = 0xFEFF; //添加这个文件头,记事本打开才能识别里面的汉字,不会乱码。
file_1.Write(&unicode, 2);
file_1.Write(path5, wcslen(path5) * sizeof(wchar_t));//日期
file_1.Write(douhao, wcslen(douhao) * sizeof(wchar_t));//逗号
file_1.Write(edit_wwid, wcslen(edit_wwid) * sizeof(wchar_t));//工号
file_1.Write(douhao, wcslen(douhao) * sizeof(wchar_t));//逗号
file_1.Write(hanzi, wcslen(hanzi) * sizeof(wchar_t));//汉字
file_1.Write(douhao, wcslen(douhao) * sizeof(wchar_t));
file_1.Write(edit_name, wcslen(edit_name) * sizeof(wchar_t));//英文名字
file_1.Write(douhao, wcslen(douhao) * sizeof(wchar_t));
file_1.Write(edit_sex, wcslen(edit_sex) * sizeof(wchar_t));//性别
file_1.Write(strEnter, wcslen(strEnter) * sizeof(wchar_t)); //换行
file_1.Close();
MessageBox(L"数据发送成功",L"cfile 提示");
}
完整代码参考:
// CFile_testDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "CFile_test.h"
#include "CFile_testDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CCFile_testDlg 对话框
CCFile_testDlg::CCFile_testDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_CFILE_TEST_DIALOG, pParent)
, edit_wwid(_T(""))
, edit_name(_T(""))
, edit_sex(_T(""))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CCFile_testDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
// DDX_Control(pDX, IDC_EDIT1_wwid, edit_wwid);
// DDX_Control(pDX, IDC_EDIT2_name, edit_name);
// DDX_Control(pDX, IDC_EDIT3_sex, edit_sex);
DDX_Text(pDX, IDC_EDIT1_wwid, edit_wwid);
DDX_Text(pDX, IDC_EDIT2_name, edit_name);
DDX_Text(pDX, IDC_EDIT3_sex, edit_sex);
}
BEGIN_MESSAGE_MAP(CCFile_testDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_Btn_Fwrite, &CCFile_testDlg::OnBnClickedBtnFwrite)
ON_BN_CLICKED(IDC_BUTTON2, &CCFile_testDlg::OnBnClickedButton2)
END_MESSAGE_MAP()
// CCFile_testDlg 消息处理程序
BOOL CCFile_testDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
edit_wwid =_T("10699487");
edit_name =L"txw";
edit_sex =L"male";
SetDlgItemText(IDC_EDIT1_wwid, edit_wwid);
SetDlgItemText(IDC_EDIT2_name, edit_name);
SetDlgItemText(IDC_EDIT3_sex, edit_sex);
//edit_name.SetWindowText(_T("stxw"));
//edit_sex.SetWindowText(_T("Male"));
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CCFile_testDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CCFile_testDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CCFile_testDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CCFile_testDlg::OnBnClickedBtnFwrite()
{
// TODO: 在此添加控件通知处理程序代码
char szCurrentDateTime[32];
char szCurrentDateTime1[32];
char path1[32] = {"d:\\txw\\"};
CString path2,path5;
CTime nowtime;
nowtime = CTime::GetCurrentTime();
sprintf_s(szCurrentDateTime, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
nowtime.GetYear(), nowtime.GetMonth(), nowtime.GetDay(),
nowtime.GetHour(), nowtime.GetMinute(), nowtime.GetSecond());
sprintf_s(szCurrentDateTime1, "%.4d-%.2d-%.2d",
nowtime.GetYear(), nowtime.GetMonth(), nowtime.GetDay());
//path2.Format(_T("%s"), szCurrentDateTime1);
strcat_s(path1, szCurrentDateTime1);
strcat_s(path1, ".txt");
path2.Format(_T("%s"), path1);
CString douhao = _T(",");
CString hanzi = _T("自然");
CString strEnter = _T("\r\n");//换行
path5 = szCurrentDateTime; //日期时间
//AfxMessageBox(path2);
CFile file_1;
file_1.Open(_T("d://txw//tt19.csv"), CFile::modeNoTruncate | CFile::modeCreate | CFile::modeWrite);//打开文件
file_1.SeekToEnd();//数据位置跳到文件末端
//WORD unicode = 0xFEFF; //这句重要
wchar_t unicode = 0xFEFF; //添加这个文件头,记事本打开才能识别里面的汉字,不会乱码。
file_1.Write(&unicode, 2);
file_1.Write(path5, wcslen(path5) * sizeof(wchar_t));//日期
file_1.Write(douhao, wcslen(douhao) * sizeof(wchar_t));//逗号
file_1.Write(edit_wwid, wcslen(edit_wwid) * sizeof(wchar_t));//工号
file_1.Write(douhao, wcslen(douhao) * sizeof(wchar_t));//逗号
file_1.Write(hanzi, wcslen(hanzi) * sizeof(wchar_t));//汉字
file_1.Write(douhao, wcslen(douhao) * sizeof(wchar_t));
file_1.Write(edit_name, wcslen(edit_name) * sizeof(wchar_t));//英文名字
file_1.Write(douhao, wcslen(douhao) * sizeof(wchar_t));
file_1.Write(edit_sex, wcslen(edit_sex) * sizeof(wchar_t));//性别
file_1.Write(strEnter, wcslen(strEnter) * sizeof(wchar_t)); //换行
file_1.Close();
MessageBox(L"数据发送成功",L"cfile 提示");
}
void CCFile_testDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
}