VC++读写文件
- 格式:pdf
- 大小:113.81 KB
- 文档页数:6
VC读写函数详解1.当前文件指针位置获取函数long ftell( FILE *stream );参数:stream 文件指针返回值:当前文件指针的位置实例:#include <stdio.h>FILE *stream;void main( void ){long position;char list[100];if( (stream = fopen( "ftell.c", "rb" )) != NULL ){/* Move the pointer by reading data: */fread( list, sizeof( char ), 100, stream );/* Get position after read: */position = ftell( stream );printf( "Position after trying to read 100 bytes: %ld\n",position );fclose( stream );}}输出:Position after trying to read 100 bytes: 1002.文件的打开函数FILE *fopen( const char *filename, const char *mode );FILE *_wfopen( const wchar_t *filename, const wchar_t *mode );参数:filename 文件的名称mode 打开文件的模式返回值:成功的打开文件的话返回文件的指针否则返回NULL表示打开文件错误注:"r"只读方式打开"w"以写入方式打开"a"从文件的尾端写入数据,要是文件不存在则创建后写入数据"r+"以读写方式打开(文件必须存在)"w+"打开一个可以读写的文件,如果该文件存在则覆盖写入"a+"打开文件并追加写入源于<stdio.h>实例:#include <stdio.h>FILE *stream, *stream2;void main( void ){int numclosed;/* Open for read (will fail if file "data" does not exist) */if( (stream = fopen( "data", "r" )) == NULL )printf( "The file 'data' was not opened\n" );elseprintf( "The file 'data' was opened\n" );/* Open for write */if( (stream2 = fopen( "data2", "w+" )) == NULL )printf( "The file 'data2' was not opened\n" );elseprintf( "The file 'data2' was opened\n" );/* Close stream */if( fclose( stream ) )printf( "The file 'data' was not closed\n" );/* All other files are closed: */numclosed = _fcloseall( );printf( "Number of files closed by _fcloseall: %u\n", numclosed ); }输出:The file 'data' was openedThe file 'data2' was openedNumber of files closed by _fcloseall: 13.文件读取函数size_t fread( void *buffer, size_t size, size_t count, FILE *stream ) 参数: buffer 文件读取缓冲区 size 读取数据的类型 count 读取数据的个数stream 文件指针返回值:实际读取的数据个数源于<stdio.h>例子:FILE* fp;char* buffer=new char[1024];long realLength=fread(buffer,sizeof(char),1024,fp);////处理过程//delete buffer;fclose(fp);4.文件的写入函数size_t fwrite( const void *buffer, size_t size, size_t count, FILE*stream );参数: buffer 所要写入文件的缓冲区 size 写入数据的类型 count 写入数据的个数 stream 文件指针返回值:实际写入的数据个数源于<stdio.h>实例:#include <stdio.h>void main( void ){FILE *stream;char list[30];int i, numread, numwritten;/* Open file in text mode: */if( (stream = fopen( "fread.out", "w+t" )) != NULL ){for ( i = 0; i < 25; i++ )list[i] = (char)('z' - i);/* Write 25 characters to stream */numwritten = fwrite( list, sizeof( char ), 25, stream );printf( "Wrote %d items\n", numwritten );fclose( stream );}elseprintf( "Problem opening the file\n" );if( (stream = fopen( "fread.out", "r+t" )) != NULL ){/* Attempt to read in 25 characters */numread = fread( list, sizeof( char ), 25, stream );printf( "Number of items read = %d\n", numread );printf( "Contents of buffer = %.25s\n", list );fclose( stream );}elseprintf( "File could not be opened\n" );}输出:Wrote 25 itemsNumber of items read = 25Contents of buffer = zyxwvutsrqponmlkjihgfedcb5.文件指针搜索函数int fseek( FILE *stream, long offset, int origin )参数: stream 文件指针 offset 从当前指针开始的偏移量 origin 文件指针当前的位置返回值:成功返回0 否则返回非零值注:指针移动的时候是按字节移动的,要是成功的话文件的指针将指向当前搜索到的位置origin 可以的取值在 stdio.h已经定义如下:SEEK_CUR当前的文件指针SEEK_END文件结束SEEK_SET文件的开始源于<stdio.h>实例:#include <stdio.h>void main( void ){FILE *stream;char line[81];int result;stream = fopen( "fseek.out", "w+" );if( stream == NULL )printf( "The file fseek.out was not opened\n" );else{fprintf( stream, "The fseek begins here: ""This is the file 'fseek.out'.\n" );result = fseek( stream, 23L, SEEK_SET);if( result )printf( "Fseek failed" );else{printf( "File pointer is set to middle of first line.\n" ); fgets( line, 80, stream );printf( "%s", line );}fclose( stream );}}输出:File pointer is set to middle of first line.This is the file 'fseek.out'.6.按固定的格式写入数据函数int fprintf( FILE *stream, const char *format [, argument ]...)int fwprintf( FILE *stream, const wchar_t *format [, argument ]...) 参数:stream 文件指针format 按照一定的格式argument 可选参数列表返回值:fprintf 返回实际写入的字节数.fwprintf返回实际写入的wchar_t 的字节数源于<stdio.h>实例:#include <stdio.h>#include <process.h>FILE *stream;void main( void ){int i = 10;double fp = 1.5;char s[] = "this is a string";char c = '\n';stream = fopen( "fprintf.out", "w" );fprintf( stream, "%s%c", s, c );fprintf( stream, "%d\n", i );fprintf( stream, "%f\n", fp );fclose( stream );system( "type fprintf.out" );}输出:this is a string101.5000007.按固定的格式读入数据函数int fscanf( FILE *stream, const char *format [, argument ]... )int fwscanf( FILE *stream, const wchar_t *format [, argument ]... ) 参数:stream 文件指针format 按照一定的格式argument 可选参数列表返回值:fscanf 返回实际读入的字节数.fwscanf返回实际读入的wchar_t 的字节数如果返回值为 0 则说明没有被赋值如果有文件结束或是异常的IO错误时返回 EOF(宏定义)源于<stdio.h>实例:#include <stdio.h>FILE *stream;void main( void ){long l;float fp;char s[81];char c;stream = fopen( "fscanf.out", "w+" );if( stream == NULL )printf( "The file fscanf.out was not opened\n" );else{fprintf( stream, "%s %ld %f%c", "a-string",65000, 3.14159, 'x' );/* Set pointer to beginning of file: */fseek( stream, 0L, SEEK_SET );/* Read data back from file: */fscanf( stream, "%s", s );fscanf( stream, "%ld", &l );fscanf( stream, "%f", &fp );fscanf( stream, "%c", &c );/* Output data read: */printf( "%s\n", s );printf( "%ld\n", l );printf( "%f\n", fp );printf( "%c\n", c );fclose( stream );}}输出:a-string650003.141590X8.文件指针的定位和获取int fsetpos( FILE *stream, const fpos_t *pos );int fgetpos( FILE *stream, const fpos_t *pos );参数:stream 目标文件指针pos 文件指针的位置返回值:设置指针位置成功的话fsetpos返回0 否则返回一个非零的数获得指针位置成功的话fgetpos返回0 否则返回一个非零的数源于<stdio.h>实例:#include <stdio.h>void main( void ){FILE *stream;fpos_t pos;char buffer[20];if( (stream = fopen( "fgetpos.c", "rb" )) == NULL )printf( "Trouble opening file\n" );else{/* Read some data and then check the position. */fread( buffer, sizeof( char ), 10, stream );if( fgetpos( stream, &pos ) != 0 )printf( "fgetpos error" );else{fread( buffer, sizeof( char ), 10, stream );printf( "10 bytes at byte %I64d: %.10s\n", pos, buffer ); }/* Set a new position and read more data */pos = 140;if( fsetpos( stream, &pos ) != 0 )printf( "fsetpos error" );fread( buffer, sizeof( char ), 10, stream );printf( "10 bytes at byte %I64d: %.10s\n", pos, buffer );fclose( stream );}}输出:10 bytes at byte 10: .C: This p10 bytes at byte 140: .C and the9.文件指针重新定位到开始void rewind( FILE *stream )参数:stream 文件指针返回值:无注:执行完本函数后,文件的指针将返回到开始位置实例:#include <stdio.h>void main( void ){FILE *stream;int data1, data2;data1 = 1;data2 = -37;if( (stream = fopen( "rewind.out", "w+" )) != NULL ){fprintf( stream, "%d %d", data1, data2 );printf( "The values written are: %d and %d\n", data1, data2 ); rewind( stream );fscanf( stream, "%d %d", &data1, &data2 );printf( "The values read are: %d and %d\n", data1, data2 );fclose( stream );}}输出:The values written are: 1 and -37The values read are: 1 and -3710.取得文件指针所指的行char *fgets( char *string, int n, FILE *stream );int fputs( const char *string, FILE *stream );参数:fgets 的string 保存到的字符串缓冲,而fputs 的string 表示要写入的字符串n表示从文件中读出的字符串不超过 n-1个字符,在读入的最后一个字符后加上串结束标志'\0'stream 文件指针返回值:成功的话返回字符数组的首地址否则返回NULL源于<stdio.h>实例:#include <stdio.h>void main( void ){FILE *stream;char line[100];if( (stream = fopen( "fgets.c", "r" )) != NULL ){if( fgets( line, 100, stream ) == NULL)printf( "fgets error\n" );elseprintf( "%s", line);fclose( stream );}fputs( "Hello world from fputs.\n", stdout );}输出:This program uses fgets to displayHello world from fputs.11.关闭文件函数int _fcloseall( void )int fclose( FILE *stream )参数:stream 文件指针返回值:fclose成功关闭返回 0 否则返回EOF 表示错误_fcloseall 成功返回总共关闭的文件数否则的话返回EOF 表示错误实例:#include <stdio.h>FILE *stream, *stream2;void main( void ){int numclosed;/* Open for read (will fail if file "data" does not exist) */if( (stream = fopen( "data", "r" )) == NULL )printf( "The file 'data' was not opened\n" );elseprintf( "The file 'data' was opened\n" );/* Open for write */if( (stream2 = fopen( "data2", "w+" )) == NULL )printf( "The file 'data2' was not opened\n" );elseprintf( "The file 'data2' was opened\n" );/* Close stream */if( fclose( stream ) )printf( "The file 'data' was not closed\n" );/* All other files are closed: */numclosed = _fcloseall( );printf( "Number of files closed by _fcloseall: %u\n", numclosed ); }输出:The file 'data' was openedThe file 'data2' was openedNumber of files closed by _fcloseall: 1完。
VC++中⽂件读写相关操作技巧CFile类的声明保存在afx.h头⽂件中。
CFile类是MFC⽂件类的基类,提供⾮缓冲⽅式的⼆进制磁盘输⼊、输出功能;并直接通过派⽣类来⽀持⽂本⽂件和内存⽂件。
提供访问本地⽂件内容的功能,不⽀持访问⽹络⽂件的功能。
CFile类的成员变量:m_hFile:表⽰⼀个打开⽂件的操作系统⽂件句柄。
通过对m_hFile 与 CFile::hFileNull的⽐较来判断该⽂件是否已经打开。
CFile类的成员函数:1、构造函数类CFile():在创建⼀个CFile对象时,我们可以采⽤3种⽅法实现。
A、CFile myFile;myFile.Open(LPCTSTR lpFileName,UINT nOpenFlags,CFileException * pError = NULL);B、CFile myFile(int hFile); 采⽤句柄⽅式创建使⽤该创建⽅法,在之前需要调⽤ CreateFile()函数,该函数的声明如下:HANDLE CreateFile(LPCTSTR lpFileName, ⽂件名称DWORD dwDesiredAccess, ⽂件访问的模式DWORD dwShareMode, ⽂件的共享模式LPSECURITY_ATTTRIBUTE lpSecurityAttribute,DWORD dwCreationDisposition, 怎么访问DWORD dwFlagsAndAttribute, ⽂件属性HANDLE hTemplateFile, 临时⽂件句柄);handle = ::CreateFile(“new.tmp”,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_ALWAYS,FILE_FLAG_DELETE_ON_CLOSE,NULL);C、CFile(LPCTSTR lpFileName,UINT nOpenFlags); ⽂件名称,可以是相对路径,绝对路径或者⽹络路径。
VC++中对文件的写入和读取本文介绍两种方法对文件进行读取和写入操作:1、采用fstream 类;2、采用CStdioFile类。
CStdioFile继承自CFile,一个CStdioFile对象代表一个用运行时函数fopen 打开的C 运行时流式文件。
C++中的fstream类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O。
stream类有两个重要的运算符:插入器(<<)和析取器(>>)。
插入器(<<)即向流输出数据,析取器(>>)即从流中输入数据。
在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。
fstream类包括向“流”输出数据的ofstream类和从“流”中输出数据的ifstream类。
1、文件的写入往文件中写入数据的操作较为简单,这里以fstream类中往文件写入数据为例,介绍VC++中对文件的写入方法。
对于用CstdioFile 类对文件进行写入操作可参看相关资料。
下面给出采用fstream类对文件进行写入操作的代码:#include <fstream.h>ofstream of1;//创建对象of1.open("数据记录.txt",ios::out,filebuf::openprot);//打开文件int i;//定义一个整型变量float f; //定义一个单精度浮点型变量double d; //定义一个双精度浮点型变量i=123;//赋值f=3.478f; //赋值d=859.653; //赋值of1<<i<<’\t’<<f<<’\t’<<d;//写入数据of1.close();//关闭文件运行后打开“数据记录.txt”文件,内容见图1,变量i,f,d已写入文件中。
C++读写文本文件#include <iostream>#include <fstream>using namespace std;int main(){const char filename[] = "mytext.txt";ofstream o_file;ifstream i_file;string out_text;//写o_file.open(filename);for (int i = 1; i <= 10; i++){o_file << "第" << i << "行\n"; //将内容写入到文本文件中}o_file.close();//读i_file.open(filename);if (i_file.is_open()){while (i_file.good()){i_file >> out_text; //将读取的内容存储到变量out_text中cout << out_text << endl; //在控制台输出读取的内容。
为什么最后一行的内容会出现两次}}elsecout << "打开文件:" << filename << " 时出错!";i_file.close();system("PAUSE");return 0;}为什么总会将最后一行显示两遍?我的循环似乎没错呀。
笔记:C++文件的读取和写入exit(1);// terminate with error}if(!outfile){cout<<"Unable to open otfile";exit(1);// terminate with error}int a,b;int i=0,j=0;int data[6][2];while(! myfile.eof()){myfile.getline(buffer,10);sscanf(buffer,"%d %d",&a,&b);cout<<a<<" "<<b<<endl;data[i][0]=a;data[i][1]=b;i++;}myfile.close();for(int k=0;k<i;k++){outfile<<data[k][0]<<" "<<data[k][1]<<endl;cout<<data[k][0]<<" "<<data[k][1]<<endl; }outfile.close();return 0;}无论读写都要包含<fstream>头文件读:从外部文件中将数据读到程序中来处理对于程序来说,是从外部读入数据,因此定义输入流,即定义输入流对象:ifsteam infile,infile就是输入流对象。
VC逐行读写文件(.TXT)时间:2010-02-05 16:22来源:未知作者:zzl 点击:1973次用流在写日志时,发现如果把"\r\n"直接写在字符串的尾部,则会造成乱码,其中的原因网上有很多说明,主要是标准库与WINDOWS的回车换行的机制略有差别。
但只要写到另一行重起就没有用流在写日志时,发现如果把"\r\n"直接写在字符串的尾部,则会造成乱码,其中的原因网上有很多说明,主要是标准库与WINDOWS的回车换行的机制略有差别。
但只要写到另一行重起就没有问题了。
/******************************************************************** ********** 写入日志文件-C++标准版(UNICODE)* 函数名:WriteLogTxt* 功能写入日志* 说明:* 参数:* 创建人:fjf* 创建时间:2009-09-10* 修改人:* 修改时间:********************************************************************* ********/bool CConLog::WriteLogTxt(CString time, CString value){//定义写入字符数组CString tmp = time + value;//定义输出流ofstream oFile;oFile.open(m_sFullName.GetBuffer(MAX_PATH),ios::app|ios::binary);oFile.seekp(0,ios::end);//回到文件末尾//写入文件流if (oFile.is_open()){//下面蓝色部分解决了CHAR[]写入的问题,不用再做拷贝了,增加了安全性oFile.write(tmp.GetBuffer(tmp.GetLength()), tmp.GetLength());oFile.write(_T("\r\n"), 2); //写在一起会产生乱码}else{oFile.close();return false;}oFile.close();return true;}/******************************************************************** ********** 写入日志文件* 函数名:WriteLogTxt* 功能写入日志* 说明:* 参数:* 创建人:fjf* 创建时间:2009-09-09* 修改人:* 修改时间:********************************************************************* ********/bool CConLog::WriteLogTxt(CString key, CString time, CString value) {//读写文件全名if (m_sFullName == _T("")){AfxMessageBox("请设置日志保存路径!");return FALSE;}//操作文件try{this->m_sfFile.Open(m_sFullName,CFile::modeCreate |CFile::modeNoTruncate | CFile::modeWrite);m_sfFile.SeekToEnd();this->m_sfFile.WriteString(time + _T("\r\n"));this->m_sfFile.WriteString(value + _T("\r\n"));this->m_sfFile.Close();}catch (CFileException &e){CString error;error.Format(_T("%d"),e.m_cause);AfxMessageBox(_T("无法写入文件!错误码:" + error));return false;}return true;}/******************************************************************** ********** 写入日志文件-C++标准版(UNICODE)* 函数名:WriteLogTxt* 功能写入日志* 说明:* 参数:* 创建人:fjf* 创建时间:2009-09-10* 修改人:* 修改时间:********************************************************************* ********/bool CConLog::WriteLogTxt(CString time, CString value){//定义写入字符数组CString tmp = time + value;//定义输出流ofstream oFile;oFile.open(m_sFullName.GetBuffer(MAX_PATH),ios::app|ios::binary);oFile.seekp(0,ios::end);//回到文件末尾//写入文件流if (oFile.is_open()){//下面蓝色部分解决了CHAR[]写入的问题,不用再做拷贝了,增加了安全性oFile.write(tmp.GetBuffer(tmp.GetLength()), tmp.GetLength());oFile.write(_T("\r\n"), 2); //写在一起会产生乱码}else{oFile.close();return false;}oFile.close();return true;}查看文章VC逐行读写日志文件(TXT)2009-11-03 11:52最近写一个日志读写控件的类,发现VC的CSdioFile的WriteString不能处理中文,虽然把字符集改成多字符形式可以解决这个问题,但这就破坏了程序的兼容性。
CFile和CStdioFile的文件读写使用方法(2009-08-18 10:35:01)标签:杂谈CFile//创建/打开文件CFile file;file.Open(_T("test.txt"),CFile::modeCreate|CFile::modeNoTruncate|CFile::modeRead Write);文件打开模式可组合使用,用“|”隔开,常用的有以下几种:CFile::modeCreate:以新建方式打开,如果文件不存在,新建;如果文件已存在,把该文件长度置零,即清除文件原有内容。
CFile::modeNoTruncate:以追加方式打开,如果文件存在,打开并且不将文件长度置零,如果文件不存在,会抛出异常。
一般与CFile::modeCreate一起使用,则文件不存在时,新建一个文件;存在就进行追加操作。
CFile::modeReadWrite:以读写方式打开文件。
CFile::modeRead:只读。
CFile::modeWrite:只写。
//写入数据CString strValue = "Hello World!";file.Write(strValue,strValue.GetLength());//追加数据file.SeekToEnd(); //将指针移至文件末尾进行追加file.Write(strValue,strValue.GetLength());//关闭文件file.Close();CStdioFileCStdioFile是CFile的派生类,对文件进行流式操作,对于文本文件的读写很有用处,可按行读取写入。
//写入数据CString strValue = "Hello World!";file.WriteString(strValue);//读取数据CString strRead;file.ReadString(strRead);当文件存在多行数据需要逐行读取时,可用函数BOOL CStdioFile::ReadString(CString& rString),当遇到"\n "时读取截断,如果文件未读完,返回true,否则返回false。
VC++添加菜单并读写ini文件数据1、打开VC++6.0,选择新建。
2、选择“工程”,选择“MFC AppWizard(exe)”,选择工程所建立的位置,并输入工程名。
单击“确定”。
3、在弹出的对话框中选择“基本对话框(D)”,点击“下一步”。
4、在弹出的想到对话框中取消“‘关于’对话框”(可省略该步)。
点击“完成”。
5、在弹出的对话框中直接点击“确定”。
6、在“ResourceView”标签下,在“Testresources”上单击右键,再弹出菜单中选择“插入”。
7、在弹出对话框中选择“Menu”,并点击“新建”。
8、弹出下面的对话框,选择“Menu”,并选中所要编辑的菜单,这里是“IDR_MENU”,在右边的编辑区编辑菜单。
9、双击菜单区中白色方框,弹出“菜单项目属性”对话框,在“标明”框中输入要显示的菜单项。
这里随便输入一个,说明操作方法和效果。
我们输入“文件(&W)”,括号内表示快捷键。
10、在“文件”菜单出现之后,其下面会再有一个白色框的空白区域,表示下拉菜单。
双击,出现“菜单项目属性”对话框,输入“ID”(必须)和“标明”,我们在“标明”中输入“操作ini\t(Ctrl+A)”,“操作ini”表示要显示的菜单项,“(Ctrl+A)”表示快捷键,“\t”会将所有下拉菜单的快捷键自动对齐。
11、还可以选择“分隔符”,在前面的小方框内打勾,会出现一个分隔符。
12、按照上述方法设计好菜单。
13、将所设计的菜单加入对话框。
在“TestDlg.cpp”的OnInitDialog函数中中加入下面代码:CMenu m_menu;m_menu.LoadMenu(IDR_MENU1);SetMenu(&m_menu);如下图所示:14、运行程序,看是否有误,如果无误,会出现下图所以的结果。
15、在“ResourceView”标签下,在“Dialog”上单击右键,再弹出菜单中选择“插入Dialog”。
目录目录第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、流IO、API之间的关系 (3)1.6 随机读写 (3)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 总结 (4)II第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);往控制台输出a bc三个字符。
1.2.2 文本文件与二进制文件读写二进制文件时,不会做任何处理,数据保持原样。
写文本文件时,V1C++会将换行符(即\n,0AH)替换为回车(即\r,0DH)和换行符;读文本文件时,VC++会将\r\n替换为\n,并且在读取到1AH时,认为文件结束。
MFC读写ini配置文件Email:liping_xiong@1.新建头文件如:ini.h,在编辑区域粘贴以下内容://///////////////////////////////////////////////////////////////////////// ini.h: interface for the Cini class.#if !defined(AFX_OPINI_H__CE3F8B7B_1ACA_46CC_A91C_F8E23FA9B063__INCLUDED _)#define AFX_OPINI_H__CE3F8B7B_1ACA_46CC_A91C_F8E23FA9B063__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#include <afxwin.h>class Cini{public:static DWORD ReadString (char *section, char * key, char stringtoread[], char * filename);static BOOL WriteString(LPCTSTR section, LPCTSTR key,char* stringtoadd, char*filename);Cini();virtual ~Cini();};#endif// !defined(AFX_OPINI_H__CE3F8B7B_1ACA_46CC_A91C_F8E23FA9B063__INCLUDED_)2.新建资源文件如:ini.cpp,在编辑区域黏贴以下内容://///////////////////////////////////////////////////////////////////////// ini.cpp: implementation of the Cini class.#include "stdafx.h"#include "ini.h"///////////////////////////////////////////////////////////////////////////Cini类的构造函数和析构函数Cini::Cini(){}Cini::~Cini(){}///////////////////////////////////////////////////////////////////////////写字符串到INI文件,GetLastError()函数用于返回写入失败void error(LPSTR lpszFunction){CHAR szBuf[80];DWORD dw = GetLastError();sprintf(szBuf, "%s failed: GetLastError returned %u\n",lpszFunction, dw);MessageBox(NULL, szBuf, "Error", MB_OK);ExitProcess(dw);}BOOL Cini::WriteString(LPCTSTR section, LPCTSTR key, char *stringtoadd, char *filename) {CHAR FilePath[255];GetModuleFileName(NULL,FilePath,255);(strrchr(FilePath,'\\'))[1] = 0;strcat(FilePath,filename);return ::WritePrivateProfileString(section,key,stringtoadd,FilePath);}///////////////////////////////////////////////////////////////////////////从INI文件中读取字符串DWORD Cini::ReadString(char *section, char * key, char stringtoread[], char * filename) {CHAR FilePath[255];GetModuleFileName(NULL,FilePath,255);(strrchr(FilePath,'\\'))[1] = 0;strcat(FilePath,filename);return ::GetPrivateProfileString(section, key,NULL,stringtoread,255,FilePath);}3.当程序加载的时候读配置文件:首先要在应用程序文件头部引用ini.h头文件如下:#include "ini.h"找到OnInitDialog()函数,在其下黏贴如下代码:// 保存ini各项值数组char szOption1[MAX_PATH];char szOption2[MAX_PATH];char szOption3[MAX_PATH];// 读取ini各项值Cini::ReadString("配置信息", "选项1", szOption1, "test.ini");Cini::ReadString("配置信息", "选项2", szOption2, "test.ini");Cini::ReadString("配置信息", "选项3", szOption3, "test.ini");m_strEdit1.Format("%s",szOption1);m_strEdit2.Format("%s",szOption2);m_strEdit3.Format("%s",szOption3);UpdateData(FALSE);说明:m_strEdit1,m_strEdit2,m_strEdit2是三个文本框对象的实例4.当卸载(关闭)程序的时候写配置文件;找到DestroyWindow()函数,在其下黏贴如下代码:UpdateData(TRUE);CString str1 = m_strEdit1;CString str2 = m_strEdit2;CString str3 = m_strEdit3;char *p1 = str1.GetBuffer(str1.GetLength()+1);char *p2 = str2.GetBuffer(str2.GetLength()+1);char *p3 = str3.GetBuffer(str3.GetLength()+1);Cini::WriteString("配置信息", "选项1", p1, "test.ini");Cini::WriteString("配置信息", "选项2", p2, "test.ini");Cini::WriteString("配置信息", "选项3", p3, "test.ini");说明:m_strEdit1,m_strEdit2,m_strEdit2是三个文本框对象的实例附工程视图及运行结果:Ini头文件Ini资源文件引用头文件引用头文件用户文件、应用程序文件对话框加载关闭对话框配置文件里的记录。
目录
目录
第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、流IO、API之间的关系 (3)
1.6 随机读写 (3)
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 总结 (4)
II
第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);往控制台输出a bc三个字符。
1.2.2 文本文件与二进制文件
读写二进制文件时,不会做任何处理,数据保持原样。
写文本文件时,V
1
C++会将换行符(即\n,0AH)替换为回车(即\r,0DH)和换行符;读文本文件时,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,则以全局变量_fmo de为准,如下面的代码将以文本模式打开文件。
_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函数有:fopen、fwrite、fread……它与低级IO最大的区别在于:低级IO无缓冲区,而流IO有缓冲区。
如:同样的写文件,_write 会直接调用WriteFile,而 fwrite 会将数据写入缓冲区,达到一定数量后,再调用 WriteFil e 将缓冲区内的数据写入文件。
显然,流IO将大大减少调用 API 函数的次数,因此理论上其效率会比较高。
2
使用setvbuf函数,可以对缓冲区的大小、行为进行设置。
VC++里,流IO由低级IO实现。
即:fopen会调用_open,fwrite会调用_ write,fgets会调用_read函数……
流IO最重大的意义在于:它是符合ANSI C 标准的一套函数,可移植性最高。
1.4 Unicode
Windows的API函数一般会分为两个版本,即处理ANSI字符串的窄字符版本,和处理Unicode字符串的宽字符版本。
低级IO和流IO也有类似的宽字符版本函数,如:_wopen、_wfopen……
使用宽字符版本的IO函数之前,一定要调用setlocale(LC_ALL,""),设置C 函数的代码页为系统默认的代码页,否则就有可能会出现乱码。
1.5 低级IO、流IO、API之间的关系
VC++中,低级 IO 由 API 实现。
使用 _open 打开一个文件,其实是调用 CreateFile 打开的文件。
因此,通过 _open 返回的文件序号,可以得到 Cr eateFile 返回的文件句柄。
_get_osfhandle 可以实现此功能。
类似的,流IO是由低级 IO 实现的。
通过调用 _fileno 函数,可以由 FI LE* 获得文件序号。
_fileno其实返回的就是FILE的成员变量_file。
通过 _open_osfhandle 函数,可以由操作系统文件句柄获得文件序号,再由 _fdopen 函数,可以通过文件序号获得FILE*。
以上过程,可以参考 MFC 源代码中的 CStdioFile::Open。
1.6 随机读写
随机读写是对文件读写的一种方式,具体表现为:
1、读或写时,会移动文件指针;
2、读、写操作交叉进行,如:读了几次后又写几次。
如果使用低级IO进行随机读写,读写函数的处理是比较简单的。
反之,
3
对于有缓冲区的流IO而言,随机读写反而可能会降低文件的读写效率。
因为以上两个操作,将频繁的清空缓冲区、移动文件指针。
可以说,在随机读写文件上,流IO并不比低级IO有优势。
1.7 C++IO流
C++的STL中,可以使用 fstream、ifstream、ofstream……对文件进行读写。
它的内部使用了流IO。
1.8 MFC
1.8.1 CFile
CFile是低级IO的C++实现。
它直接调用 API,主要用于读写二进制文件。
1.8.2 CStdioFile
CStdioFile用于读写文本文件,具体的就是读写一行行的文本。
它内部调用了流IO。
当以 Unicode 编译程序时,CStdioFile 将调用 Unicode 版本的流IO函数,此时一定要首先调用 setlocale(LC_ALL,"")。
还需要说明的一点是:从 EVC3.0 至 VC2008,CStdioFile 都是无法正常运行在 Windows CE 平台上的。
1.8.3 CArchive
CArchive 主要用于串行化,它可以与 CFile 或 CMemFile 关联,然后通过<<和>>方便的实现变量的串行化和反串行化。
CArchive 与 CFile 关联,串行化时变量将保存至文件。
CArchive 与 CMemFile 关联,串行化时变量将保存至内存。
CArchive 与CSocketFile关联,串行化时变量将通过套接字传输到网络。
1.9 总结
如果使用C语言,可以选择使用API、低级IO、流IO。
如果代码要移植
4
到其它平台,建议使用流IO。
如果使用C++语言,上述方法均可使用。
读写二进制文件相对比较容易,比较复杂的是读写文本文件。
复杂在两个方面:
1、各个操作系统定义的行结束符不尽相同,如:Linux定义\r为行结束符,Mac定义\n为行结束符,Windows定义\r\n为行结束符。
而且,还需要考虑各个操作系统之间的文件读写,如:Linux生成的文本文件在Windows下读取……
2、必须考虑多种编码。
如:Windows平台下,文本文件分为四种格式:A NSI、UTF16LE、UTF16BE、UTF-8。
VC++6.0只支持读写ANSI编码的文本文件。
自VC++2005开始,fopen增加了对UTF16LE、UTF-8这两种编码的支持,不过这种支持不适用于 Windows CE 平台。
上述两个问题,最好的解决办法就是自行编写一个处理文本文件的C++类。
5。