fopen_s
, _wfopen_s
打开文件。 这些版本的 fopen
、_wfopen
具有安全性增强功能,如 CRT 中的安全性功能中所述。
语法
errno_t fopen_s(
FILE** pFile,
const char *filename,
const char *mode
);
errno_t _wfopen_s(
FILE** pFile,
const wchar_t *filename,
const wchar_t *mode
);
参数
pFile
指向文件指针的指针,该指针接收指向打开的文件的指针。
filename
要打开的文件的名称。
mode
允许的访问类型。
返回值
如果成功,则为零;如果失败,则为错误代码。 有关这些错误代码的详细信息,请参阅 errno
、_doserrno
、_sys_errlist
和 _sys_nerr
。
错误条件
pFile |
filename |
mode |
返回值 | pFile 的内容 |
---|---|---|---|---|
NULL |
any | 任意 | EINVAL |
未更改 |
any | NULL |
任意 | EINVAL |
未更改 |
any | 任意 | NULL |
EINVAL |
未更改 |
备注
fopen_s
和 _wfopen_s
函数无法打开用于共享的文件。 如果需要共享文件,请将 _fsopen
或 _wfsopen
与适当的共享模式常量配合使用(例如,将 _SH_DENYNO
用于读/写共享)。
fopen_s
函数打开由 filename
指定的文件。 _wfopen_s
是 fopen_s
的宽字符版本,_wfopen_s
的参数是宽字符字符串。 除此以外,_wfopen_s
和 fopen_s
的行为完全相同。
fopen_s
接受执行时文件系统上有效的路径;fopen_s
接受 UNC 路径以及包含所映射网络驱动器的路径,前提是执行代码的系统在执行时能够访问共享或映射的网络驱动器。 为 fopen_s
构造路径时,请勿做出有关驱动器、路径或执行环境中网络共享的可用性假设。 可使用斜杠 (/) 或反斜杠 (\) 作为路径中的目录分隔符。
这些函数验证其参数。 如果 pFile
、filename
或 mode
为 null 指针,则这些函数将生成无效的参数异常,如参数验证中所述。
请始终先检查返回值,确定该函数是否成功,再对文件执行任何进一步的操作。 如果出现错误,则将返回错误代码并且将设置全局变量 errno
。 有关详细信息,请参阅errno
, _doserrno
, _sys_errlist
和_sys_nerr
.
默认情况下,此函数的全局状态范围限定为应用程序。 若要更改此状态,请参阅 CRT 中的全局状态。
Unicode 支持
fopen_s
支持 Unicode 文件流。 若要打开新的或现有的 Unicode 文件,请将指定所需编码的 ccs
标志传递到 fopen_s
,例如:
fopen_s(&fp, "newfile.txt", "w+, ccs=UNICODE");
ccs
标志的允许值为 UNICODE
、UTF-8
和 UTF-16LE
。 如果未为 ccs
指定值,则 fopen_s
将使用 ANSI 编码。
如果文件已存在并已打开以进行读取或追加,则字节顺序标记 (BOM)(如果文件中存在)将确定编码。 BOM 编码优先于 ccs
标志指定的编码。 仅在不存在 BOM 或如果文件是新文件时,才使用 ccs
编码。
注意
BOM 检测仅适用于在 Unicode 模式下打开的文件;即,通过传递 ccs
标志打开的文件。
下表汇总了提供给 fopen_s
的各种 ccs
标志值的模式以及文件中的 BOM 的模式。
基于 ccs
标志和 BOM 使用的编码
ccs 标志 |
无 BOM(或新文件) | BOM:UTF-8 | BOM:UTF-16 |
---|---|---|---|
UNICODE |
UTF-8 |
UTF-8 |
UTF-16LE |
UTF-8 |
UTF-8 |
UTF-8 |
UTF-16LE |
UTF-16LE |
UTF-16LE |
UTF-8 |
UTF-16LE |
在 Unicode 模式下打开用于写入的文件将自动在其中写入 BOM。
如果 mode
为 "a, ccs=UNICODE"
、"a, ccs=UTF-8"
或 "a, ccs=UTF-16LE"
,fopen_s
将先尝试使用读取和写入访问权限打开文件。 如果成功,此函数将读取 BOM 以确定文件的编码;如果失败,此函数将使用文件的默认编码。 在任一情况下,fopen_s
随后均将使用只写访问权限重新打开文件。 (此行为仅适用于 a
模式,不适用于 a+
模式。)
字符串 mode
指定对文件请求的访问类型,如下所示。
mode |
Access |
---|---|
"r" |
打开以便读取。 如果文件不存在或找不到,fopen_s 调用将失败。 |
"w" |
打开用于写入的空文件。 如果给定文件存在,则其内容会被销毁。 |
"a" |
在文件末尾打开以进行写入(追加),在新数据写入到文件之前不移除文件末尾 (EOF) 标记。 如果文件不存在,则创建文件。 |
"r+" |
打开以便读取和写入。 文件必须存在。 |
"w+" |
打开用于读取和写入的空文件。 如果文件存在,则其内容会被销毁。 |
"a+" |
打开以进行读取和追加。 追加操作包括在新数据写入文件之前移除 EOF 标记。 写入完成后,EOF 标记不会还原。 如果文件不存在,则创建文件。 |
通过使用 "a"
或 "a+"
访问类型打开文件时,所有写入操作均将在文件末尾进行。 使用 fseek
或 rewind
可重新定位文件指针,但在执行任何写入操作前,文件指针将始终被移回文件末尾,以确保不会覆盖现有数据。
在 EOF 标记追加到文件之前,"a"
模式会将其删除。 追加后,MS-DOS TYPE
命令仅显示原始 EOF 标记之前的数据,不显示追加到文件的任何数据。 在 EOF 标记追加到文件之前,"a+"
模式会将其删除。 在追加后,MS-DOS TYPE
命令显示文件中的所有数据。 需使用 "a+"
模式才能附加到通过 CTRL
+Z EOF 标记终止的流文件。
当指定 "r+"
、"w+"
或 "a+"
访问类型时,允许读取和写入。 (文件据说已经可以进行“更新”。)但是,当你从读取切换到写入时,输入操作必定会遇到 EOF 标记。 如果没有 EOF 标记,必须使用对文件定位函数的干预调用。 文件定位函数是 fsetpos
、fseek
和 rewind
。 从写入切换到读取时,必须使用对 fflush
或文件定位函数的干预调用。
从 C11 开始,可以将 "x"
追加到 "w"
,或追加 "w+"
以使函数在该文件存在时失败,而不是覆盖该文件。
除了上述值之外,可以在 mode
中包含以下字符以指定换行符的转换模式:
mode 修饰符 |
转换模式 |
---|---|
t |
在文本(转换)模式下打开。 输入时,回车换行 (CR-LF) 组合将转换为单一的换行 (LF);输出时,LF 字符将转换为 CR-LF 组合。 CTRL+Z 将在输入时解释为文件尾字符。 |
b |
在二进制(未转换)模式下打开;禁止涉及回车和换行字符的转换。 |
在文本(已转换)模式中,CTRL
+Z 将在输入时解释为文件结尾字符。 在打开使用 "a+"
进行读取/写入的文件中,fopen_s
将检查文件末尾的 CTRL
+Z 并在可能的情况下将其删除。 将其删除是因为使用 fseek
和 ftell
在以 CTRL
+Z 结尾的文件中移动时,可能导致 fseek
在文件末尾附近错误运行。
另外,在文本模式下,输入时,回车/换行 (CRLF) 组合将转换为单一的换行 (LF) 字符;输出时,LF 字符将转换为 CRLF 组合。 当 Unicode 流 I/O 函数在文本模式(默认设置)下运行时,源或目标流将假定为一系列多字节字符。 Unicode 流输入函数将多字节字符转换为宽字符(就像调用 mbtowc
函数一样)。 出于同一原因,Unicode 流输出函数将宽字符转换为多字节字符(就像调用 wctomb
函数一样)。
如果 t
或 b
在 mode
中未给出,则默认转换模式由全局变量 _fmode
定义。 如果 t
或 b
是该参数的前缀,则函数将失败并返回 NULL
。
有关在 Unicode 和多字节流 I/O 中使用文本和二进制模式的详细信息,请参阅文本和二进制模式文件 I/O 和文本和二进制模式下的 Unicode 流 I/O。
mode 修饰符 |
行为 |
---|---|
c |
启用关联 filename 的提交标志,以便在调用 fflush 或 _flushall 时将文件缓冲区的内容直接写入磁盘。 |
n |
将关联的 filename 的提交标志重置为“no-commit”。此标志为默认值。 如果将程序显式链接到 COMMODE.OBJ ,它还将重写全局提交标志。 除非将程序显式链接到 COMMODE.OBJ ,否则全局提交标志默认为 "no-commit"(请参阅链接选项)。 |
N |
指定文件不由子进程继承。 |
S |
指定缓存针对(但不限于)从磁盘的顺序访问进行优化。 |
R |
指定缓存针对(但不限于)从磁盘的随机访问进行优化。 |
T |
指定一个文件,除非内存压力需要它,否则不会写入磁盘。 |
D |
指定在关闭最后一个指向该文件的指针时删除的临时文件。 |
ccs=UNICODE |
指定 UNICODE 作为要用于此文件的编码字符集。 如果需要 ANSI 编码,请不要指定此字符集。 |
ccs=UTF-8 |
指定 UTF-8 作为要用于此文件的编码字符集。 如果需要 ANSI 编码,请不要指定此字符集。 |
ccs=UTF-16LE |
指定 UTF-16LE 作为要用于此文件的编码字符集。 如果需要 ANSI 编码,请不要指定此字符集。 |
在 fopen_s
和 _fdopen
中使用的 mode
字符串的有效字符对应于在 _open
和 _sopen
中使用的 oflag
参数,如下所示。
字符串中的 mode 字符 |
_open /_sopen 的等效 oflag 值 |
---|---|
a |
_O_WRONLY | _O_APPEND (通常为 _O_WRONLY | _O_CREAT | _O_APPEND ) |
a+ |
_O_RDWR | _O_APPEND (通常为 _O_RDWR | _O_APPEND | _O_CREAT ) |
R |
_O_RDONLY |
r+ |
_O_RDWR |
w |
_O_WRONLY (通常为 _O_WRONLY | _O_CREAT | _O_TRUNC ) |
w+ |
_O_RDWR (通常为 **_O_RDWR | _O_CREAT | _O_TRUNC ) |
b |
_O_BINARY |
t |
_O_TEXT (翻译) |
c |
无 |
n |
无 |
D |
_O_TEMPORARY |
R |
_O_RANDOM |
S |
_O_SEQUENTIAL |
T |
_O_SHORTLIVED |
ccs=UNICODE |
_O_WTEXT |
ccs=UTF-8 |
_O_UTF8 |
ccs=UTF-16LE |
_O_UTF16 |
c
、、n
R
、S
、t
和 T
mode
D
选项Microsoft扩展fopen_s
_wfopen_s
,并且不应在需要 ANSI 可移植性时使用。
如果使用 rb
模式,并且无需移植代码、预计将读取大量文件或者不关心网络性能,则内存映射的 Win32 文件可能也是一个选项。
关于 T
和 D
:
- 只要内存压力不需要,
T
就避免将文件写入磁盘。 有关详细信息,请参阅文件属性常量中的FILE_ATTRIBUTE_TEMPORARY
,以及此博客文章它只是暂时性的。 D
指定写入磁盘的常规文件。 区别在于它在关闭时会自动删除。 可以组合TD
来获取这两种语义。
要求
函数 | 必需的标头 | C++ 标头 |
---|---|---|
fopen_s |
<stdio.h> |
<cstdio> |
_wfopen_s |
<stdio.h> 或 <wchar.h> |
<cstdio> |
有关 C 运行时库中的标准符合性和命名约定的详细信息,请参阅兼容性。
一般文本例程映射
<tchar.h> 例程 |
_UNICODE 和 _MBCS 未定义 |
_MBCS 已定义 |
_UNICODE 已定义 |
---|---|---|---|
_tfopen_s |
fopen_s |
fopen_s |
_wfopen_s |
库
C 运行时库的所有版本。
示例
// crt_fopen_s.c
// This program opens two files. It uses
// fclose to close the first file and
// _fcloseall to close all remaining files.
#include <stdio.h>
FILE *stream, *stream2;
int main( void )
{
errno_t err;
// Open for read (will fail if file "crt_fopen_s.c" doesn't exist)
err = fopen_s( &stream, "crt_fopen_s.c", "r" );
if( err == 0 )
{
printf( "The file 'crt_fopen_s.c' was opened\n" );
}
else
{
printf( "The file 'crt_fopen_s.c' was not opened\n" );
}
// Open for write
err = fopen_s( &stream2, "data2", "w+, ccs=UTF-8" );
if( err == 0 )
{
printf( "The file 'data2' was opened\n" );
}
else
{
printf( "The file 'data2' was not opened\n" );
}
// Close stream if it isn't NULL
if( stream )
{
err = fclose( stream );
if ( err == 0 )
{
printf( "The file 'crt_fopen_s.c' was closed\n" );
}
else
{
printf( "The file 'crt_fopen_s.c' was not closed\n" );
}
}
// All other files are closed:
int numclosed = _fcloseall( );
printf( "Number of files closed by _fcloseall: %u\n", numclosed );
}
The file 'crt_fopen_s.c' was opened
The file 'data2' was opened
Number of files closed by _fcloseall: 1
另请参阅
流 I/O
fclose
, _fcloseall
_fdopen
, _wfdopen
ferror
_fileno
freopen
, _wfreopen
_open
, _wopen
_setmode