最近程序中打开文件时,失败了,最后代码问题在:

  fopen_s(&pFile,strPath.c_str(),"rb+");

主要是"rb+"。


首先来看下介绍,主要是windows下的CRT相关的文件打开操作了。

C89标准中是 fopen:

FILE * fopen(const char *file, const char *mode);

windows中有fopen_s,_fsopen的扩展:

errno_t fopen_s(
   FILE** pFile,
   const char *filename,
   const char *mode
);

FILE *_fsopen(
   const char *filename,
   const char *mode,
   int shflag
);

通过看vs2008/2010下CRT的源码我们可以看到 fopen、fopen_s都是通过调用_fsopen来实现的:

FILE * fopen(const char *file, const char *mode)
{
    return( _fsopen(file, mode, _SH_DENYNO) );
}

errno_t fopen_s(FILE ** pfile, const char *file, const char *mode)
{
    _VALIDATE_RETURN_ERRCODE((pfile != NULL), EINVAL);
    *pfile = _fsopen(file, mode, _SH_SECURE);

    if(*pfile != NULL)
        return 0;
    return errno;
}

主要也就在于_fsopen的第3个参数了:int shflag:

#define _SH_DENYRW      0x10    /* deny read/write mode */
#define _SH_DENYWR      0x20    /* deny write mode */
#define _SH_DENYRD      0x30    /* deny read mode */
#define _SH_DENYNO      0x40    /* deny none mode */
#define _SH_SECURE      0x80    /* secure mode */

而通过源码中可看到,所谓的_SH_SECURE就是  /* share read access only if read-only */

所以区别就在于fopen是_SH_DENYNO即共享读写,而fopen_s是_SH_SECURE即在只读模式下才共享读,其他时不共享。

所以回到一开始的问题,之所以读文件失败,是因为几个进程同时在读这个文件,而模式用的是"rb+"即打开是为了读和写的,所以fopen_s会被一个进程锁住,不共享给其他进程。解决方案就是将"rb+"改成"rb"即只读模式,就可以了。

总结:打开文件时,能尽量减少读写标志就尽量减少,尤其是很多时候只需要只读就可以了,就不要加可写。