C/C++,Win32,MFC文件操作汇总
首先文件操作是无外乎是对文件打开,关闭,读写等操作,每一种语言都有对相关文件的操作接口,现在主要做一些搜集与整理,作为一些参考:
一、C语言文件操作
C语言中没有输入输出语句,所有的输入输出功能都用 ANSI C提供的一组标准库函数来实现。文件操作标准库函数有:
一、C语言文件操作
C语言中没有输入输出语句,所有的输入输出功能都用 ANSI C提供的一组标准库函数来实现。
文件操作标准库函数有:
fopen 打开一个文件
fclose 关闭一个文件
fputc 写一个字符到文件中去
fgetc 从文件中读取一个字符
fgets 从文件中读取一个字符串
fputs 写一个字符串到文件中去
fprintf 往文件中写格式化数据
fscanf 格式化读取文件中数据
fread 以二进制形式读取文件中的数据
fwrite 以二进制形式写数据到文件中去
getw 以二进制形式读取一个整数
putw 以二进制形式存贮一个整数
文件状态检查函数
feof 文件结束
ferror 文件读/写出错
clearerr 清除文件错误标志
ftell 了解文件指针的当前位置
文件定位函数 rewind 反绕
fseek 随机定位
相关函数原型:
1.打开文件
FILE *fopen(char *pname,char *mode)
2.关闭文件
int fclose(FILE *fp);
3.从文件中读取一个字符
int fgetc(FILE *fp);
4.写一个字符到文件中去
int fputc(int ch,FILE *fp)
5.从文件中读取一个字符串
char *fgets(char *str,int n,FILE *fp)
6.写一个字符串到文件中去
int fputs(char *str,FILE *fp)
7.往文件中写格式化数据
int fprintf(FILE *fp,char *format,arg_list)
8.以二进制形式读物文件中数据
int fread(void *buffer,unsigned sife,unsigned count,FILE *fp)
9.以二进制形式写入文件数据
int fwrite(void *buffer,unsigned sife,unsigned count,FILE *fp)
10.以二进制形式读取一个整数
int getw(FILE *fp)
11.以二进制形式存储一个整数
int putw(int n,FILE *fp)
12.文件状态检查
int feof(FILE *fp)
13.文件读/写出错
int ferror(FILE *fp)
14.清除文件错误标志
void clearerr(FILE *fp)
15.文件定位
void rewind(FILE *fp)
16.随机定位
int fseek(FILE *fp,long offset,int base)
17.关于exit()函数
void exit(int status)
18.关于feof()函数
int feof(FILE *fp)
文件打开模式:
“r” 只读
从文件起始位置开始读。 注意:文件不存在时,打卡失败。
“r+” 读写(以读为主)
文件不存在时,打开失败。
文件存在时,如果没设置文件指针,文件指针指向文件首。
“w” 只写
文件不存在时,创建文件。
文件存在时,清空文件,文件指针指向文件首。
“w+” 写读(以写为主)
文件不存在时,创建文件。
文件存在时,清空文件,文件指针指向文件首。
“a” 追加写(只写)
文件不存在时,创建文件。
文件存在时,文件指针指向文件尾。(在文件为追加,即用fseek()函数无效)
“a+” 追加读写(读写)
文件不存在时,创建文件。
文件存在时:
写:追加写(文件指针设置无效)
读:先设置文件指针,写完之后文件指针在文件尾(最初,文件指针在文件首)
实例:1.利用feof()函数检查文件是否读取完毕
#include
int main()
{
FILE *fp;
fp = fopen("d:\\curFile.txt", "r");
if(fp != NULL){
while(!feof(fp))
printf("%c", fgetc(fp));
}else{
printf("file open failed! \n");
}
fclose(fp);
return 0;
}
2.利用文件结束标志EOF(即-1)
#include
main()
{
char ch;
FILE *fp;
fp = fopen("d:\\curFile.txt", "r");
if(fp != NULL){
ch = fgetc(fp);
while(ch != EOF) {
printf("%c", ch);
ch = fgetc(fp);
}
}else {
printf("file open failed! \n");
}
fclose(fp);
return 0;
}
3.fputc()函数的使用
#include
main()
{
FILE *fp;
if((fp=fopen("d:\\curFile.txt","w"))==NULL){
printf("a.txt open failed ! \n");
return 1;
}
int i;
for(i=0; i<10; i++){
putc('w',fp); //写10个'w'到curFile.txt文件中
}
fclose(fp);
return 0;
}
4.fwrite函数使用
#include
int main()
{
int str[10] = {1,2,3,4,5,6,7,8,9,0};
FILE *fp ;
if((fp = fopen("a.txt","w") )== NULL){
printf("file open failed!\n");
}
fwrite(str,sizeof(int),10,fp);
fclose(fp);
return 0;
}
5.fread函数:
#include
int main()
{
int str[10] ;
FILE *fp ;
if((fp = fopen("a.txt","r") )== NULL){
printf("file open failed!\n");
}
fread(str,sizeof(int),10,fp);
int i;
for(i=0; i<10; i++){
printf("%d ",str[i]);
}
printf("\n");
fclose(fp);
return 0;
}
二、C++文件读写:
每种语言系统都会提供IO操作的类库,用于对预定义类型数据进行输入输出的操作。C++也是如此,它是以字节流的形式实现的。在输入操作时,字节流从输入设备(键盘、磁盘)流向内存;
在输出操作时,字节流由内存流向输出设备(显示器、打印机);字节流可以是ASCII字符、二进制数据、图形图像、音频视频等信息。文件和字符串也可以看成是有序的字节流,又称为文件
流和字符串流。C++的编译系统自带一个面向对象的输入输出软件包,即IO流类库。库中各种类的声明都被包含在相应的头文件中,比如之前经常用到的头文件iostream,其中使用的cin\cout
都是常用的流对象,用于对标准设备的IO操作。还有用于用户文件管理IO操作的fstream头文件(磁盘文件的操作),用于字符串流的IO操作的strstream头文件(内存字符流的操作),以及iomanip
头文件用于输入输出的格式控制。有两个抽象基类ios和iostream,输入流类:istream,ifstream和 istrstream;输出流类:ostream,ofstream和ostrsream;输入输出流类:iostream,
fstream。ios是抽象基类,类istream和ostream是单继承于ios,而类iostream是通过多继承于类istream和类ostream。ios除了派生出istream和ostream还派生出fstreambase文件流类和
strstreambase串流类,而该4类又派生出ifstream、ofstream、istrstream、ostrstream,以及fstream和strstream。
ios::in = 0x01, //供读,文件不存在则创建(ifstream默认的打开方式)
ios::out = 0x02, //供写,文件不存在则创建,若文件已存在则清空原内容(ofstream默认的打开方式)
ios::ate = 0x04, //文件不存在时,生成空文件;文件不存在,清空原文件(ofstream打开方式)。如果没有文件,打开失败;如果有文件,定位到文件尾,但是不能写文件(ifstream打开方式)。
ios::app = 0x08, //供写,文件不存在则创建,若文件已存在则在原文件内容后写入新的内容,指针位置总在最后
ios::trunc = 0x10, //在读写前先将文件长度截断为0(默认)
ios::nocreate = 0x20, //文件不存在时产生错误,常和in或app联合使用
ios::noreplace = 0x40, //文件存在时产生错误,常和out联合使用
ios::binary = 0x80 //二进制格式文件
filebuf::openprot; //默认的兼容共享方式
filebuf::sh_none; //独占,不共享
filebuf::sh_read; //读共享
filebuf::sh_write; //写共享
以上方式仅旧版VC中支持,新版VC在share.h中为Win32项目定义了如下方式[1]
_SH_DENYRW 0x10 /* deny read/write mode*/
_SH_DENYWR 0x20 /* deny write mode */
_SH_DENYRD 0x30 /* deny read mode */
_SH_DENYNO 0x40 /* deny none mode */
_SH_SECURE 0x80 /* secure mode */
fstream // 文件流
ifstream // 输入文件流
ofstream // 输出文件流
ifstream和ofstream都提供了成员函数来重定位文件定位指针(文件中下一个被读取或写入的字节号)
在ifstream中 这个成员函数为seekg("seek get");在ofstream中为seekp("seek put")
seekg(绝对位置); //绝对移动, //输入流操作
seekg(相对位置,参照位置); //相对操作
tellg(); //返回当前指针位置
seekp(绝对位置); //绝对移动, //输出流操作
seekp(相对位置,参照位置); //相对操作
tellp()和tellg()成员函数分别用来返回当前get和put的指针位置
参照位置:
ios::beg = 0 //相对于文件头
ios::cur = 1 //相对于当前位置
ios::end = 2 //相对于文件尾
1.读写文本文件的示例:
//为能够正确读出写入文件的各数据,各数据间最好要有分隔
#include
void main()
{
fstream f("d:\\try.txt",ios::out);
f<<1234<<' '<<3.14<<'A'<<"How are you"; //写入数据
f.close();
f.open("d:\\try.txt",ios::in);
int i;
double d;
char c;
char s[20];
f>>i>>d>>c; //读取数据
f.getline(s,20);
cout< cout< cout< cout< f.close();
}
2.创建一个文本文件并写入信息
//同向屏幕上输出信息一样将信息输出至文件
#include
#include
void main()
{
ofstream f1("d:\\me.txt"); //打开文件用于写,若文件不存在就创建它
if(!f1)return; //打开文件失败则结束运行
f1< f1< f1.close(); //关闭文件
}
3.使用get()一次读一个字节
#include
void main()
{
ifstream fin("d:\\简介.txt",ios::nocreate);
if(!fin){
cout<<"File open error!\n";
return;
}
char c;
while((c=fin.get())!=EOF)cout< fin.close();
}
4.使用get(char *,int n,char delim='\n')一次读多个字符
//巧妙利用文本文件中不会有字符'\0'的特点进行读取
#include
void main()
{
ifstream fin("d:\\简介.txt",ios::nocreate);
if(!fin){
cout<<"File open error!\n";
return;
}
char c[80];
while(fin.get(c,80,'\0')!=NULL)cout< fin.close();
}
5.使用read(char *,int n)读文件
#include
void main()
{
ifstream fin("d:\\简介.txt",ios::nocreate);
if(!fin){
cout<<"File open error!\n";
return;
}
char c[80];
while(!fin.eof()) //判断文件是否读结束
{
fin.read(c,80);
cout.write(c,fin.gcount());
}
fin.close();
}
6.文件的拷贝
//二进制文件操作示例
#include
void main()
{
ifstream fin("C:\\1.exe",ios::nocreate|ios::binary);
if(!fin){
cout<<"File open error!\n";
return;
}
ofstream fout("C:\\2.exe",ios::binary);
char c[1024];
while(!fin.eof())
{
fin.read(c,1024);
fout.write(c,fin.gcount());
}
fin.close();
fout.close();
cout<<"Copy over!\n";
三、Win32文件读写
在Win32系统下文件可以支持平常的同步读写和异步读写(但在Win9X下,Win32系统不支持磁盘文件的异步读写)。本节在后面部分将会介绍文件的异步读写,最后一段内容将向大家讲解一下文
件的区域加锁。Win32系统中支持64位长度的文件,所以在很多文件操作函数中需要两个DWORD参数来表示文件长度,一个DWORD用来表示低32位,另一个用来表示高32位。文件的读写进行在文件
被正确打开后,但请确认在打开文件时设置了正确的读写标记。在Win32的文件操作中没有了以前类似与以前ANSI C中的fputs fgets fprintf fscanf等函数,只有类似于fread和fwrite的
ReadFile和WriteFile函数。
ReadFile用于文件读,函数原型为:
BOOL ReadFile(
HANDLE hFile, // handle to file
LPVOID lpBuffer, // data buffer
DWORD nNumberOfBytesToRead, // number of bytes to read
LPDWORD lpNumberOfBytesRead, // number of bytes read
LPOVERLAPPED lpOverlapped // overlapped buffer
);
其中各项参数的含义为:
hFile:文件句柄,为CreateFile时返回的句柄
lpBuffer:保存读入的数据的指针
nNumberOfBytesToRead:指定需要读入的字节数
lpNumberOfBytesRead:返回实际读入的字节数
lpOverlapped:在文件异步读写时使用的数据,在同步读写中全部都设置为NULL,在Win9X中只支持对串口的异步操作。
如果返回值为FALSE并且读入的字节数也返回为0,则表示文件到达了末尾。
WriteFile用于文件写,函数原型为:
BOOL WriteFile(
HANDLE hFile, // handle to file
LPCVOID lpBuffer, // data buffer
DWORD nNumberOfBytesToWrite, // number of bytes to write
LPDWORD lpNumberOfBytesWritten, // number of bytes written
LPOVERLAPPED lpOverlapped // overlapped buffer
);
参数的含义和ReadFile类似。
如果需要移动文件指针到相关位置(和文件读写不同,这个函数没有异步版本),使用
DWORD SetFilePointer(
HANDLE hFile, // handle to file
LONG lDistanceToMove, // bytes to move pointer
PLONG lpDistanceToMoveHigh, // bytes to move pointer
DWORD dwMoveMethod // starting point
);
其中各项参数的含义为:
hFile:文件句柄,为CreateFile时返回的句柄
lpBuffer:保存读入的数据的指针
lDistanceToMove:移动的字节数低DWORD
lpDistanceToMoveHigh:移动的字节数高DWORD,为了支持64位(2的64次方字节)长度的大文件,而用来指定64字节的高32位,如果文件大小只需要32位就可以表示,则设置为NULL
ldwMoveMethod:移动方法,可以选择下面的值。
FILE_BEGIN 从文件开始处开始移动
FILE_CURRENT 从文件开始除开始移动
FILE_END 从文件末尾开始移动
1.打开创建文件
HANDLE hFile = ::CreateFile(TEXT("E:\\CreateFileDemo.txt"), //创建文件的名称。
GENERIC_WRITE|GENERIC_READ, // 写和读文件。
0, // 不共享读写。
NULL, // 缺省安全属性。
CREATE_ALWAYS, // 如果文件存在,也创建。
FILE_ATTRIBUTE_NORMAL, // 一般的文件。
NULL); // 模板文件为空。
if (hFile == INVALID_HANDLE_VALUE)
{
OutputDebugString(TEXT("CreateFile fail!\r\n"));
}
2.写入文件
const int BUFSIZE = 4096;
char chBuffer[BUFSIZE];
memcpy(chBuffer,"Test",4);
DWORD dwWritenSize = 0;
BOOL bRet = ::WriteFile(hFile,chBuffer,4,&dwWritenSize,NULL);
if (bRet)
{
OutputDebugString(TEXT("WriteFile 写文件成功\r\n"));
}
3.读取文件
DWORD dwReadSize = 0;
::ZeroMemory(chBuffer,4096);
bRet = ::ReadFile(hFile,chBuffer,4,&dwReadSize,NULL);
if (bRet)
{
OutputDebugString(TEXT("ReadFile 读文件成功\r\n"));
}
else
{
//获取出错码。
DWORD dwError = GetLastError();
//处理出错。
TCHAR chErrorBuf[1024];
wsprintf(chErrorBuf,TEXT("GetLastError()=%d\r\n"),dwError);
OutputDebugString(chErrorBuf);
}
4.设置文件读写位置
LONG lDistance = 0;
DWORD dwPtr = SetFilePointer(hFile, lDistance, NULL, FILE_BEGIN);
SetEndOfFile函数,将当前文件位置设为文件末尾,GetFileSizeEx返回文件末尾大小
::SetEndOfFile(hFile);
LARGE_INTEGER liFileSize;
::GetFileSizeEx(hFile,&liFileSize);
四、MFC文件读写
MFC文件读写分为两种一种文件流读写,另外一种为文件映射
文件流读写:
1.CFile文件打开方式:
CFile::modeCreate
创建新文件,如果文件已存在,则将其长度变成0
CFile::modeNoTruncate
与modeCreate组合使用,如果文件已存在,则不会将其长度变成0
CFile::modeRead
以只读方式打开文件
CFile::modeReadWrite
以读写方式打开文件
CFile::modeWrite
以只写方式打开文件
CFile::modeNoInherit
组织该文件被子项继承
CFile::shareDenyNone
以共享模式打开文件,不会禁止其他进程对文件的读写
CFile::shareDenyRead
禁止其他进程对文件的读操作
CFile::shareDenyWrite
禁止其他进程对文件的写操作
CFile::shareExclusive
以独占模式打开文件,禁止其他进程对文件的读写
CFile::typeText
以文本方式打开文件
CFile::typeBinary
以二进制方式打开文件
2. CFile操作函数
函数
含义
Open
打开文件
Close
关闭文件
Flush
刷新待写的数据
Read
从当前位置读取数据
Write
向当前位置写入数据
GetLength
获取文件的大小
Seek
定位文件指针至指定位置
SeekToBegin
定位文件指针至文件头
SeekToEnd
定位文件指针至文件尾
GetFileName
获取文件名,如:“NOTEPAD.EXE”
GetFilePath
获取文件路径,如:“C:\WINDOWS \NOTEPAD.EXE”
GetFileTitle
获取文件标题,如:“NOTEPAD”
GetPosition
获取当前文件指针
GetStatus
获取当前文件的状态,返回一个CFileStatus
#Remove
静态方法,删除指定文件
#Rename
静态方法,重命名指定文件
写入文件:
CFile file;
file.Open("E:\\VC\\1.txt",CFile::modeCreate|CFile::modeWrite|CFile::modeNoTruncate,NULL);
file.Write("HelloWorld",strlen("121212aaaa"));
file.close( );
读取文件:
CFile file;
file.Open("E:\\VC\\1.txt",CFile::modeRead,NULL);
DWORD len=file.GetLength( );
char Buf[len+1];
Buf[len]=0; //0终止字符串,用于输出。
file.Read(Buf,len); //Read( void* lpBuf, UINT nCount ) lpBuf是用于接收读取到的数据的Buf指针nCount是从文件读取的字节数
MessageBox(Buf);
文件映射:
void main(int argc, char* argv[])
{
// 创建文件对象(C: est.tsr)
HANDLE hFile = CreateFile("C:/test.tsr", GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("创建文件对象失败,错误代码:%d ", GetLastError());
return;
}
// 创建文件映射对象
HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hFileMap == NULL)
{
printf("创建文件映射对象失败,错误代码:%d ", GetLastError());
return;
}
// 得到系统分配粒度
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
DWORD dwGran = SysInfo.dwAllocationGranularity;
// 得到文件尺寸
DWORD dwFileSizeHigh;
__int64 qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);
qwFileSize |= (((__int64)dwFileSizeHigh) << 32);
// 关闭文件对象
CloseHandle(hFile);
// 偏移地址
__int64 qwFileOffset = 0;
// 块大小
DWORD dwBlockBytes = 1000 * dwGran;
if (qwFileSize < 1000 * dwGran)
dwBlockBytes = (DWORD)qwFileSize;
if (qwFileOffset >= 0)
{
// 映射视图
TCHAR *lpbMapAddress = (TCHAR *)MapViewOfFile(hFileMap,FILE_MAP_ALL_ACCESS,
0, 0,
dwBlockBytes);
if (lpbMapAddress == NULL)
{
printf("映射文件映射失败,错误代码:%d ", GetLastError());
return;
}
//-----------------------访问数据开始-------------------------
cout< getchar();
//-----------------------访问数据结束-------------------------
// 撤销文件映像
UnmapViewOfFile(lpbMapAddress);
}
// 关闭文件映射对象句柄
CloseHandle(hFileMap);
}
string GetValue(const TCHAR *lpbMapAddress, const TCHAR *sName)
{
string sValue; // 存放 = 后面的value值
TCHAR *p1 = NULL, *p2 = NULL; // 字符指针
if((p1 = strstr(lpbMapAddress,sName)) != NULL) // 查找sName出现位置
{
if(p2 = strstr(p1,"/r/n")) *p2 = '/0'; // 查找"/r/n"(换行)出现位置
sValue = p1+strlen(sName)+strlen("="); // 指针移动"sName"+"="之后
*p2 = '/r'; // 还原*p2值,因为不还原会改变原文件结构
}
return sValue;
}
在处理一般的文件(文本/非文本),这些足够了。然而在处理比较大的文件如
几十M, 几百M, 甚至上G的文件, 这时再用一般手段处理,系统就显的力不从心了
要把文件读出,再写进,耗费的是CPU利用率与内存以及IO的频繁操作,
文件映射可以很好解决这个问题。