在编程读取文本文件的时候,经常被不同的编码格式所混乱。文本的默认编码格式是ANSI码,后来国际化了又支持了Unicode编码格式,现在打开Windows平台下记事本,点击“另存为”就可以发现有四种编码方式可以选择保存。如图。
其中,ANSI没有BOM值,下面三种都有BOM值。UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。所以出现了UTF-16有大尾小尾编码之分,UTF-8有BOM值的以及没有BOM值之差,但是UTF-8有没有BOM值不影响解码。网上有很多处理文本文件编码问题的源码,我借鉴了CTextFileIO(http://www.codeproject.com/KB/files/TextFileIO.aspx)并进行修改添加等等,主要是添加了对NO BOM的UTF-8的判断。下面表格说明各种编码方式的BOM值不同。
编码方式 | BOM值 |
ANSI | 无 |
Unicode | FF FE |
Unicode big endian | FE FF |
UTF-8 | EF BB BF |
UTF-8 NO BOM | 无 |
使用到工程示例:
环境:Visual Studio 2008 SP1
1.创建一个对话框TestTextFile工程,使用Unicode库,其余默认;
2.在界面上放置两个Edit,两个Button,其中做为显示的CEdit的属性为Multiline为TRUE、Want return为TRUE、Horizontal scroll为TRUE、Vertical scroll为TRUE;
3.把TextFileIO.h、TextFileIO.cpp添加到工程,然后在对话框头文件添加以下代码:
4.为“文件”CEdit添加CString变量m_filename,为显示CEdit添加CString变量m_text;
5.为“浏览”按钮添加事件响应:
{
CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
_T( "文本文件 (*.txt)|*.txt|所有文件 (*.*)|*.*||"));
if(dlg.DoModal()==IDOK)
{
m_text=_T( "");
UpdateData(FALSE);
m_filename = dlg.m_ofn.lpstrFile;
CTextFileIO configFile;
configFile.Open(m_filename);
switch (configFile.GetEncodingType())
{
case 0:
SetDlgItemText(IDC_CODE_STATIC,_T( "ANSI"));
break;
case 1:
SetDlgItemText(IDC_CODE_STATIC,_T( "UTF16_LE"));
break;
case 2:
SetDlgItemText(IDC_CODE_STATIC,_T( "UTF16_BE"));
break;
case 3:
SetDlgItemText(IDC_CODE_STATIC,_T( "UTF_8"));
break;
case 4:
SetDlgItemText(IDC_CODE_STATIC,_T( "UTF_8NB"));
break;
}
configFile.Read(m_text);
UpdateData(FALSE);
}
}
6.为“写入保存”按钮添加事件:
{
UpdateData();
if (m_filename.IsEmpty())
return;
CTextFileIO configFile;
configFile.Open(m_filename,_T( "wb"));
int lineCount,i,len;
CString strText;
lineCount=((CEdit*)GetDlgItem(IDC_SHOWFILE_EDIT))->GetLineCount();
for (i= 0;i<lineCount;i++)
{
strText=_T( "");
len=((CEdit*)GetDlgItem(IDC_SHOWFILE_EDIT))->LineLength(((CEdit*)GetDlgItem(IDC_SHOWFILE_EDIT))->LineIndex(i));
((CEdit*)GetDlgItem(IDC_SHOWFILE_EDIT))->GetLine(i,strText.GetBuffer(len),len);
strText.ReleaseBuffer();
TRACE(_T( "It is %s/n"),strText);
configFile.WriteLine(strText);
}
AfxMessageBox(_T( "写入保存成功!"));
}
7.编译运行,结果如下图所示:
这个源码支持多字节/Unicode工程,当不同工程时,会自动判断读取文本文件到给定的变量中,不需要再因为工程的不同而改动源码。