网络上资源如此详实,习惯了使用一些开源库或者使用网上的一小段的代码来完成功能,因此对一些基本的概念渐渐的开始淡忘,今天在编写柜位预测编码时涉及到了C/C++文件存取的操作,因此今天特整理了一下这方面的相关知识。
1.文件操作相关的基本概念
1)数据流
程序与数据的交互以流的形式进行。
2)缓冲区
用于存放准备执行的数据。在文件操作中,有两种方式进行文件处理:
a.通过缓冲区进行文件处理
该方式是使用较低级的I/O函数(包含在io.h和fcntl.h)来直接对磁盘进行存取。这种方式存取速度慢,同时不是C++的标准函数,不适配多平台。
b.直接对磁盘中的文件进行操作
该方式是使用I/O函数(包含在头文件cstdio中),系统会自动设置缓冲区,通过数据流来读写文件。
读文件时,先打开数据流将磁盘上的文件信息拷贝到缓冲区内,在从缓冲区读取所需数据。
写文件时,则是先写入缓冲区,当关闭文件流时,将缓冲区中的信息存入磁盘。
3)文件类型
a.文本文件
以字符编码的方式进行保存的,只是计算机以二进制表示数据在外部存储介质上的另一种存放形式.它所存放的每一个字节都可以转换为一个可读字符当向文件中写入数据时,一旦遇到"换行"字符(ASCII 码为10)则会转换成"回车-换行"(ASCII 值为13,10).在读取数据的时候,一遇到"回车-换行"的组合 ASCII 值为13,10),则会转换成为"换行"字符(ASCII 码为10)
b.二进制文件
将内存中数据原封不动的读取和写入文件中
4)文件存取方式
a.顺序存取
从上往下,读取或者写入数据
b.随机存取
多以二进制为主,一般以一个完整的单位来进行数据的读取和写入
注:stdio.h与cstdio的区别
C是C++的一个子集,且C++中,已不推荐再用C的类库,但为了对已有代码的保护,还是对原来的头文件支持。
cstdio是c++从C的stdio.h继承来的,在前面加C同时不要H后缀,在C++环境当然是选用前者,两者内容都一样,只是cstdio头文件中定义的名字被定义在命名空间std中
2.C进行文件存取操作
#include "stdio.h" #include "stdlib.h" void main( ) { FILE *fp; int i; struct stu{ char name[20]; char stuNO[10]; float score[2]; }student; if((fp=fopen("stuinfo.txt","wb"))==NULL) { printf("cannot open file"); exit(0); } printf("input data:/n"); for( i=0;i<2;i++) { scanf("%s %s %f %f",student.name,student.stuNO,&student.score[0],&student.score[1]); //fprintf(fp,"%s %s %7.2f %7.2f/n",student.name,student.stuNO,student.score[0],student.score[1]); /* 格式化写入文件*/ fwrite(&student,sizeof(student),1,fp); /*以块的形式写入文件*/ } fclose(fp); if((fp=fopen("stuinfo.txt","rb"))==NULL) { printf("cannot open file"); exit(0); } printf("output from file:/n"); //while (fscanf(fp,"%s %s %f %f/n",student.name,student.stuNO,&student.score[0],student.score[1])!=EOF)/ *从文件格式化读入* / //{ // printf("%s %s %7.2f %7.2f/n",student.name,student.stuNO,student.score[0],student.score[1]); //} for (i=0;i<2;i++) { fread(&student,sizeof(student),1,fp); /*以块的形式读入文件*/ printf("%s %s %7.2f %7.2f/n",student.name,student.stuNO,student.score[0],student.score[1]); } fclose(fp); // FILE *fp1,*fp2; // char str[128]; // if ((fp1=fopen("test1.txt","r"))==NULL)/* 以只读方式打开文件1 */ // { // printf("cannot open file/n"); // exit(0); // } // if((fp2=fopen("test2.txt","w"))==NULL)/*以只写方式打开文件2 */ // { // printf("cannot open file/n"); // exit(0); // } // while ((strlen(fgets(str,128,fp1)))>0)/*从文件中读回的字符串长度大于0 */ // { // fputs(str,fp2 ); /* 从文件1读字符串并写入文件2 */ // printf("%s",str); /*在屏幕显示*/ // } // fclose(fp1); // fclose(fp2); }
上面这段代码涉及到C文件操作的如下函数:fopen、fclose、fputs、fgets、fwrite、fread、fprintf、fscanf
fopen用于打开文件,其第二个参数表示以什么方式打开文件,第二个参数解释如下:
"r"(只读) 为输入打开一个文本文件,"w"(只写)为输出打开一个文本文件
"a"(追加) 为追加打开一个文本文件,"rb"(只读)为输入打开一个二进制文件
"wb"(只写) 为输出打开一个二进制文件,"ab"(追加)为追加打开一个二进制文件
"r+"(读写) 为读/写打开一个文本文件,"w+"(读写)为读/写创建一个文本文件
"a+"(读写) 为读/写打开一个文本文件,"rb+"(读写)为读/写打开一个二进制文件
"wb+"(读写) 为读/写创建一个二进制文件,"ab+"(读写)为读/写打开一个二进制文件
下面是其他的文件操作函数的解释:
分类
|
函数名
|
功能
|
打开文件
|
fopen() |
打开文件。 |
关闭文件
|
fclose()
|
关闭文件。 |
文件定位
|
fseek() rewind() ftell() |
改变文件位置指针位置 使文件位置指针重新置于文件开头 返回文件位置指针的当前值 |
文件读写
|
fgetc(),getc() fputc(),putc() fgets() fputs() getw() putw() fread() fwrite() fscanf() fprintf() |
从指定文件取得一个字符。 把字符输出到指定文件。 从指定文件读取字符串。 把字符串输出到指定文件。 从指定文件读取一个字(int型)。 把一个字(int型)输出到指定文件。 从指定文件中读取数据项。 把数据项写到指定文件。 从指定文件按格式输入数据。 按指定格式将数据写到指定文件中。 |
文件状态
|
feof() ferror() clearerr() |
若到文件末尾,函数值为“真”(非0)。 若对文件操作出错,函数值为“真”(非0)。 使ferror和feof函数值置零。 |
C++使用这类函数最好是引用cstdio这个头文件。
3.C++文件操作
#include "stdafx.h" #include <iostream> #include <fstream> #include <string> using namespace std; typedef struct stu { char name[20]; int age; char num[10]; }student; int main(int argc, _TCHAR* argv[]) { student s; s.name[20]=(char)"fengshuiyue"; s.age=21; s.num[10]=(char)"88888888"; ofstream sf("data.dat",ios_base::out|ios_base::ass|ios_base::binary); sf.write((char*)&s,sizeof(s)); sf.close(); ifstream in("data.dat",ios_base::in|ios_base::binary); student s1; in.read((char*)&s1,sizeof(s1)); in.close(); cout<<s1.age<<endl<<s1.name<<endl<<s1.num<<endl; return 0; }
上面涉及到的C++的文件的类如下:ifstream(文件读操作)、ofstream(文件写操作)
打开文件的方式在ios类(所以流式I/O的基类)中定义,有如下几种方式:
ios::in为输入(读)而打开文件
ios::out 为输出(写)而打开文件
ios::ate 初始位置:文件尾
ios::app 所有输出附加在文件末尾
ios::trunc 如果文件已存在则先删除该文件
ios::binary 二进制方式
以上方式可以通过“|”进行组合。
4.通过fstream与fread、fwrite在读写方面的效率
有人做过测试,测试结果是:
1)在写文件方面 fwrite() > ofstream.operator<<() > ofstream.write()
2)在读文件方面 读取一个 100M 的文件, fread() 的效率 是 ifstream.read()的将近十倍
原因是:C++的输入输出不要告诉其数据类型,而是采用重载实现的,这个当然比C耗时了。C在读取的时候,都有格式控制符来告诉数据类型的。一般来说,gets比scanf快,scanf比cin快。
5.其他库中的文件操作
1)boost
boost FileSystem Library提供了安全、可移植且易用的c++接口,用于执行文件系统操作。
其详细介绍可参考:了解 Boost Filesystem Library
2)Poco
不同操作系统中数据代表的数据不同,POCO目前支持Windows、UNIX相关系统和OpenVMS。Poco库的文件系统包括以下类:Poco::Path、Poco::File、Poco::TemporaryFile、Poco::DirectoryIterator、Poco::Glob
注:boost库和Poco库的文件操作完成了遍历目录及拷贝文件等操作,其并未实现文件的读写,故文件读写仍需用传统的方式(使用cstdio中函数或者fstream中类)来完成。