文件操作总结:关于文本和二进制流(typeText&typeBinary)

时间:2023-03-09 02:05:34
文件操作总结:关于文本和二进制流(typeText&typeBinary)

本人能力、精力有限,所言所感都基于自身的实践和有限的阅读、查阅,如有错误,欢迎拍砖,敬请赐教——博客园:钱智慧。

总结:

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'的解释。见代码:

 // TODO: 在此添加控件通知处理程序代码
char* str="It's length is 20\nab";
CStdioFile f1;
CStdioFile f2;
f1.Open(TEXT("D:\\std_bin.txt"),CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyNone);
f1.Write(str,strlen(str));
f1.Close(); f2.Open(TEXT("D:\\std_text.txt"),CFile::modeCreate| CFile::modeWrite | CFile::typeText | CFile::shareDenyNone);
f2.Write(str,strlen(str));
f2.Close();

运行后会发现std_text.txt比std_bin.txt大一个字节,因为typeText模式下,写入字符串str时,会把\n扩展成\r\n写入到文件中。以后你必须再以typeText模式去读这个文件,\r\n才会再替换成\n。不然,会怎么样呢:

 //for循环执行前,std_text.txt在磁盘上,长度是21个字节
for (int i=;i<;++i)
{
//循环里的逻辑是:先将std_text.txt以typeBinary模式式读进来,然后再
//用typeText模式写出去 CStdioFile f;
f.Open(TEXT("D:\\std_text.txt"),CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone);
CFileStatus status;
f.GetStatus(TEXT("D:\\std_text.txt"),status);
//由于我们用于显示,只是用缓冲区承载读进来的文件内容,所以不考虑字符0
char* str=new char[status.m_size];
f.Read(str,status.m_size);
f.Close();
f.Open(TEXT("D:\\std_text.txt"),CFile::modeWrite | CFile::typeText | CFile::shareDenyNone);
f.Write(str,status.m_size);
f.Close();
}

初始内容就是第一段代码生成的,第二段代码(上面的代码)运行后,会发现std_text.txt在磁盘上的长度增加了100个字节。

所以,为了避免这种情况,最好遵循一个原则:以什么方式写就以什么方式读,这有点类似涉及到编码的文件读写了。