赞
踩
MFC 读写 文件 内容 包含 中文 英文 数字
CStdioFile-derived class for multibyte and Unicode reading and writing
https://www.codeproject.com/Articles/4119/CStdioFile-derived-class-for-multibyte-and-Unicode
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); }
转自: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); }
ANSI 与utf-8的读取方法
https://blog.csdn.net/s634772208/article/details/71437603
问题
以CFile::typeBinary的形式读写包含中文的文件,未出现乱码。
以CFile::typeText方式读写, 分两种情况:在多字节字符集下,使用CStdioFile::ReadString读取包含中文的文件,正常;工程编码切换至UNICODE字符集,则出现了中文乱码。
从以上信息中提取到关键信息:
在文本模式下,使用UNICODE版本的IO操作函数(如_wfopen,
fgetws等)时,函数会假定操作的对象是多字节序列(即文件存放的是多字节内容)。这些函数内部会做转换,比如读取时,就会将多字节序列转换成宽字节;写入时,就会将宽字节转换成多字节序列。
在二进制模式下,函数会假定操作的对象是UNICODE序列(即文件存放的是UNICODE内容,即每个字符都用二或四(极少的情况下)个字节存储在文件中,除非显式写入,否则文件中不带BOM头)
全部都是论坛上找到的代码,自己整理了一下,主要目的是方便以后自己查找使用。
判断文件是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); }
检查字符集是否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: 在此添加控件通知处理程序代码 }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。