这个恐怕是一个很奇怪的问题,甚至我在上发帖的时候,有人这样回答“因为如果叫成CTextFile,你肯定要问 CTextFile为什么不叫CStdioFile?”。
也有人比较认真的说“CStdioFile类既可以对文本文件进行操作也可以对二进制文件进行操作,他有Write(),Read()等方法,而不公是WriteString(),ReadString()。很明显不能叫CTextFile,看名字会认识是专门对文件文件进行访问的”。的确,类库的类名都是经过认真确认以保证能够正确描述类的功能,但作为一个继承类关键是要说明新添加的功能(基类的功能肯定是要继承来的),所以上面的说法未免有点牵强。
要说为什么,首先我们要看看什么是TextFile。我们都知道在CFile类中提供了2种模式,typeBinary和typeText。如果是CTextFile类的话当然要强制使用typeText类型了。那么CStdioFile是怎么做的呢?
BOOL CStdioFile::Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pException)
{
…
/// 调用基类打开文件,注意通过nOpenFlags & ~typeText过滤了文件的文本属性
if (!CFile::Open(lpszFileName, (nOpenFlags & ~typeText), pException))
return FALSE;
…
/// 转换打开模式
if (nOpenFlags & typeBinary)
szMode[nMode++] = 'b', nFlags ^= _O_TEXT;
else
szMode[nMode++] = 't';
…
// open a C-runtime low-level file handle
int nHandle = _open_osfhandle((UINT_PTR) m_hFile, nFlags);
// open a C-runtime stream from that handle
if (nHandle != -1)
m_pStream = _fdopen(nHandle, szMode);
…
}
由上面的代码可以看出,CStdioFile强制过滤了typeText标志,使得文件打开模式可以是二进制模式。这已经可以证明CStdioFile不是一个纯粹TextFile类。再仔细看上面的代码,在调用基类打开后,又使用_open_osfhandle和_fdopen做了奇怪的转换,察看m_pStream的类型
FILE* m_pStream; // stdio FILE
这是一个标准I/O的FILE结构。如果再进一步的研究CStdioFile的源码,还会发现它都是调用标准I/O的函数来操作的,比如用_fputts/_fgetts来实现WriteString/ReadString,用fread/fwrite/fseek来替代Read/Write/Seek。注意CStdioFile并没有使用CFile的Read/Write/Seek函数,如果在Open里将使用fopen直接打开的话,CStdioFile甚至可以说和CFile没有任何的关系。,由此这个类叫做CStdioFile就不奇怪了。
为什么要研究这个问题呢?前一段在上看到不少人问为什么UNICODE的文本文件处理出现乱码?他们很惊异发现平常作为TextFile的处理类用得CStdioFile竟然失效了。真的是它失效了吗?其实是标准的I/O操作并不支持UNICODE的模式而已。