VC++读写文件

1 读写文件    1

1.1 API    1

1.2 低级IO    1

1.2.1 文件序号    1

1.2.2 文本文件与二进制文件    1

1.3 IO    2

1.4 Unicode    3

1.5 IO、低级IOAPI之间的关系    3

1.6 随机读写    4

1.7 C++IO    4

1.8 MFC    4

1.8.1 CFile    4

1.8.2 CStdioFile    4

1.8.3 CArchive    4

1.9 总结    5

 

1 读写文件

1.1 API

使用VC++读写文件,最直接、最高效的方法就是使用 Windows API,如:使用 CreateFile 打开文件,使用 WriteFile 写文件,使用 ReadFile 读文件……Windows 平台下,所有对文件的读写操作,最终都会调用这些 API 函数。使用 API 的效率最高,对文件读写的控制最强,缺点就是比较复杂,而且代码没有可移植性。

1.2 低级IO

为了方便移植 UNIX C代码,VC++C运行时库实现了一套低级IO函数,如:_open_write_read……

1.2.1 文件序号

_open返回的是一个整数,MSDN上称其为文件句柄(file handle),这与CreateFile返回的文件句柄容易混淆。为此,本文称_open返回的为文件序号。

VC++中,系统预先打开了三个文件,其文件序号如下表所示

文件序号

stdin 

0 

标准输入设备,一般就是键盘

stdout 

1 

标准输出设备,一般就是控制台

stderr 

2 

标准错误输出设备,一般就是控制台

也就是说,无需调用_open,可以直接调用_write(1,"abc",3);往控制台输出abc三个字符。

1.2.2 文本文件与二进制文件

读写二进制文件时,不会做任何处理,数据保持原样。写文本文件时,VC++会将换行符(即\n0AH)替换为回车(即\r0DH)和换行符;读文本文件时,VC++会将\r\n替换为\n,并且在读取到1AH时,认为文件结束。

_open函数里可以指定文件模式,

如:_open("c:\\1.txt",_O_RDONLY | _O_TEXT);     //文本模式

如:_open("c:\\1.txt",_O_RDONLY | _O_BINARY);     //二进制模式

如果_open函数里未指定 _O_TEXT _O_BINARY,则以全局变量_fmode为准,如下面的代码将以文本模式打开文件。

_fmode = _O_TEXT;

_open("c:\\1.txt",_O_RDONLY);

假定c:\1.txt的内容如下:

1 

2 

3 

\r 

\n 

4 

5 

6 

\r 

\n 

执行如下代码:

int    n = _open("c:\\1.txt",_O_RDONLY | _O_BINARY);

char    str[128];

_read(n,str,128);

_close(n);

str的内容将是"123\r\n456\r\n"。将_O_BINARY替换为_O_TEXT,则str的内容将变为"123\n456\n"。可见\r\n如期的被替换为\n。不过,需要注意的是:将\r\n替换为\n是在第二个参数内进行的,如:将_read(n,str,128);替换为下面两行代码:

_read(n,str,4);    //读取到"123\r"

_read(n,str,4);    //读取到"\n456"

这个时候,\r\n就不会被替换为\n。这点要特别注意。

1.3 IO

IO函数有:fopenfwritefread……它与低级IO最大的区别在于:低级IO无缓冲区,而流IO有缓冲区。如:同样的写文件,_write 会直接调用 WriteFile,而 fwrite 会将数据写入缓冲区,达到一定数量后,再调用 WriteFile 将缓冲区内的数据写入文件。显然,流IO将大大减少调用 API 函数的次数,因此理论上其效率会比较高。

使用setvbuf函数,可以对缓冲区的大小、行为进行设置。

VC++里,流IO由低级IO实现。即:fopen会调用_openfwrite会调用_writefgets会调用_read函数……

IO最重大的意义在于:它是符合ANSI C 标准的一套函数,可移植性最高。

1.4 Unicode

WindowsAPI函数一般会分为两个版本,即处理ANSI字符串的窄字符版本,和处理Unicode字符串的宽字符版本。低级IO和流IO也有类似的宽字符版本函数,如:_wopen_wfopen……

使用宽字符版本的IO函数之前,一定要调用setlocale(LC_ALL,""),设置 C 函数的代码页为系统默认的代码页,否则就有可能会出现乱码。

1.5 IO、低级IOAPI之间的关系

三者的关系如下图所示:流IO由低级IO实现,而低级IOAPI实现。

函数_fileno可根据流IOFILE*获得低级IO的文件序号;

函数_get_osfhandle可根据低级IO的文件序号获得API的文件句柄;

函数_open_osfhandle可根据API的文件句柄获得低级IO的文件序号;

函数_fdopen可根据低级IO的文件序号获得流IOFILE*

1.6 随机读写

随机读写是对文件读写的一种方式,具体表现为:

1、读或写时,会移动文件指针;

2、读、写操作交叉进行,如:读了几次后又写几次。

如果使用低级IO进行随机读写,读写函数的处理是比较简单的。反之,对于有缓冲区的流IO而言,随机读写反而可能会降低文件的读写效率。因为以上两个操作,将频繁的清空缓冲区、移动文件指针。可以说,在随机读写文件上,流IO并不比低级IO有优势。

1.7 C++IO

C++STL中,可以使用 fstreamifstreamofstream……对文件进行读写。它的内部使用了流IO

1.8 MFC

1.8.1 CFile

CFile是低级IOC++实现。它直接调用 API,主要用于读写二进制文件。

1.8.2 CStdioFile

CStdioFile用于读写文本文件,具体的就是读写一行行的文本。它内部调用了流IO。当以 Unicode 编译程序时,CStdioFile 将调用 Unicode 版本的流IO函数,此时一定要首先调用 setlocale(LC_ALL,"")。还需要说明的一点是:从 EVC3.0 VC2008CStdioFile 都是无法正常运行在 Windows CE 平台上的。

1.8.3 CArchive

CArchive 主要用于串行化,它可以与 CFile CMemFile 关联,然后通过<<>>方便的实现变量的串行化和反串行化。

CArchive CFile 关联,串行化时变量将保存至文件。

CArchive CMemFile 关联,串行化时变量将保存至内存。

CArchive CSocketFile关联,串行化时变量将通过套接字传输到网络。

1.9 总结

如果使用C语言,可以选择使用API、低级IO、流IO。如果代码要移植到其它平台,建议使用流IO。如果使用C++语言,上述方法均可使用。

读写二进制文件相对比较容易,比较复杂的是读写文本文件。复杂在两个方面:

1、各个操作系统定义的行结束符不尽相同,如:Linux定义\r为行结束符,Mac定义\n为行结束符,Windows定义\r\n为行结束符。而且,还需要考虑各个操作系统之间的文件读写,如:Linux生成的文本文件在Windows下读取……

2、必须考虑多种编码。如:Windows平台下,文本文件分为四种格式:ANSIUTF16LEUTF16BEUTF-8VC++6.0只支持读写ANSI编码的文本文件。自VC++2005开始,fopen增加了对UTF16LEUTF-8这两种编码的支持,不过这种支持不适用于 Windows CE 平台。

上述两个问题,最好的解决办法就是自行编写一个处理文本文件的C++类。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【前言】 工作或学习中可能需要实现基于VC读\Excel文件的功能,本人最近也遇到了该问题。中间虽经波折,但是最终还是找到了解决问题的办法。 在此跟大家分享,希望对跟我同样迷茫过的同学们有所帮助。 1、程序功能 1)打开一个excel文件; 2)显示到CListCtrl上; 3)新建一个Excel文件。 以上均在对话框中实现。 2、平台 VC++2010 3、实现方法 常用的Excel打开方式有两种 1)通过数据库打开; 2)OLE方式打开。 由于方式1)操作繁琐,经常出现莫名的错误,这里选用方式2). 4、准备步骤 首先新建一个Dialog窗体程序,添加list control和两个按钮 1)将ExcelLib文件夹拷贝到程序目录下; 2)将Export2Excel.h,Export2Excel.cpp两个文件添加到项目; 3)包含头文件,#include "ExcelLib/Export2Excel.h" 通过以上步骤在程序中引入了可以读取Excle文件的CExport2Excel类; 5、打开excel文件 通过按钮点击打开 void CExcelTestDlg::OnBnClickedButtonOpenExcel() { //获取文件路径 CFileDialog* lpszOpenFile; CString szGetName; lpszOpenFile = new CFileDialog(TRUE,"","",OFN_FILEMUSTEXIST|OFN_HIDEREADONLY,"Excel File(*.xlsx;*.xls)|*.xls;*.xlsx",NULL); if (lpszOpenFile->DoModal()==IDOK) { szGetName = lpszOpenFile->GetPathName(); SetWindowText(szGetName); delete lpszOpenFile; } else return; //打开文件 //文件中包含多个sheet时,默认打开第一个sheet CExport2Excel Excel_example; Excel_example.OpenExcel(szGetName); //获取sheet个数 int iSheetNum = Excel_example.GetSheetsNumber(); //获取已使用表格行列数 int iRows = Excel_example.GetRowCount(); int iCols = Excel_example.GetColCount(); //获取单元格的内容 CString cs_temp = Excel_example.GetText(1,1); //AfxMessageBox(cs_temp); //List control上显示 //获取工作表列名(第一行) CStringArray m_HeadName; m_HeadName.Add(_T("ID")); for (int i=1;iGetItemCount()>0) { m_list.DeleteColumn(0); } //初始化ClistCtrl,加入列名 InitList(m_list,m_HeadName); //填入内容 //第一行是标题,所以从第2行开始 CString num; int pos; for (int row = 2;row<=iRows; row++) { pos = m_list.GetItemCount(); num.Format(_T("%d"),pos +1); m_list.InsertItem(pos,num); for (int colum=1;columDoModal()==IDOK) { szGetName = lpszOpenFile->GetPathName(); SetWindowText(szGetName); delete lpszOpenFile; } else return; //文件全名称 CString csFileName = szGetName; //需要添加的两个sheet的名称 CString csSheetName = "newSheet"; CString csSheetName2 = "newSheet2"; // 新建一个excel文件,自己入文字 CExport2Excel Excel_example; //新建excel文件 Excel_example.CreateExcel(csFileName); //添加sheet,新加的sheet在前,也就是序号为1 Excel_example.CreateSheet(csSheetName); Excel_example.CreateSheet(csSheetName2); //操作最开始添加的sheet:(newSheet) Excel_example.SetSheet(2); //添加表头 Excel_example.WriteHeader(1,"第一列"); Excel_example.WriteHeader(2,"第二列"); //添加核心数据 Excel_example.WriteData(1,1,"数据1"); Excel_example.WriteData(1,2,"数据2"); //保存文件 Excel_example.Save(); //关闭文件 Excel_example.Close(); } 7、注意事项 1)一般单个Excel文件包含多个sheet,程序默认打开第一个; 2)指定操作sheet,使用Excel_example.SetSheet(2)函数; 3)打开文件时最左侧的sheet序号为1,新建excel时最新添加的sheet序号为1. 【后记】 本程序主要基于网络CSDN中---“Excel封装库V2.0”---完成,下载地址是:http://download.csdn.net/detail/yeah2000/3576494,在此表示感谢!同时, 1)在其基础上作了小改动,改正了几个小错误,添加了几个小接口; 2)添加了如何使用的例子,原程序是没有的; 3)详细的注释 发现不足之处,还请大家多多指教!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值