本人能力、精力有限,所言所感都基于自身的实践和有限的阅读、查阅,如有错误,欢迎拍砖,敬请赐教——博客园:钱智慧。
总结:
CFile,其自身是不提供缓冲区的(?但CFile又有一个Flush,这一点目前我还没弄明白),配合CArchive(CArchive类似一个缓冲区)为MFC的类提供序列化机制。文本的格式化输出建议用ofstream或者CStdioFile(通过CString配合)。可以通过构造绑定文件,采用typeBinary模式,不能使用typeText模式。是MFC文件操作体系中的基类。其静态成员函数(如GetStatus,配合CFileStatus)可以在不打开文件的情况下获取文件的相关信息,如长度,通过CFileStatus的m_size),或者进行相关操作:如删除、重命名。
CStdioFile,必须通过Open绑定文件,默认采用typeText模式,作为CFile子类,可以使用typeText,也可以使用typeBinary。
fstream是basic_fstream模板类的一个实例,关于文本和二进制,其默认模式是文本,可以通过指定ios::binary指明二进制模式,否则采取默认值。但要注意这是char版本的类。如果要技术Unicode,则需要用wfstream。如果通过fstream来获取文件大小,只能通过指针偏移,这一点不如CFileStatus配合CFile::GetStatus来得简便。
文本和二进制流:
区别在于读写时,对'\n'的解释。见代码:
1 // TODO: 在此添加控件通知处理程序代码 2 char* str="It's length is 20\nab"; 3 CStdioFile f1; 4 CStdioFile f2; 5 f1.Open(TEXT("D:\\std_bin.txt"),CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyNone); 6 f1.Write(str,strlen(str)); 7 f1.Close(); 8 9 10 f2.Open(TEXT("D:\\std_text.txt"),CFile::modeCreate| CFile::modeWrite | CFile::typeText | CFile::shareDenyNone); 11 f2.Write(str,strlen(str)); 12 f2.Close();
运行后会发现std_text.txt比std_bin.txt大一个字节,因为typeText模式下,写入字符串str时,会把\n扩展成\r\n写入到文件中。以后你必须再以typeText模式去读这个文件,\r\n才会再替换成\n。不然,会怎么样呢:
1 //for循环执行前,std_text.txt在磁盘上,长度是21个字节 2 for (int i=0;i<100;++i) 3 { 4 //循环里的逻辑是:先将std_text.txt以typeBinary模式式读进来,然后再 5 //用typeText模式写出去 6 7 CStdioFile f; 8 f.Open(TEXT("D:\\std_text.txt"),CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone); 9 CFileStatus status; 10 f.GetStatus(TEXT("D:\\std_text.txt"),status); 11 //由于我们用于显示,只是用缓冲区承载读进来的文件内容,所以不考虑字符0 12 char* str=new char[status.m_size]; 13 f.Read(str,status.m_size); 14 f.Close(); 15 f.Open(TEXT("D:\\std_text.txt"),CFile::modeWrite | CFile::typeText | CFile::shareDenyNone); 16 f.Write(str,status.m_size); 17 f.Close(); 18 }
初始内容就是第一段代码生成的,第二段代码(上面的代码)运行后,会发现std_text.txt在磁盘上的长度增加了100个字节。
所以,为了避免这种情况,最好遵循一个原则:以什么方式写就以什么方式读,这有点类似涉及到编码的文件读写了。