fopen_wfopen

打开文件。 这些执行更多参数验证并返回错误代码的函数有更安全的版本可用;请参阅 fopen_s, _wfopen_s

语法

FILE *fopen(
   const char *filename,
   const char *mode
);
FILE *_wfopen(
   const wchar_t *filename,
   const wchar_t *mode
);

参数

filename
文件名。

mode
启用的访问类型。

返回值

这些函数均返回指向打开文件的指针。 一个 null 指针值指示错误。 如果 filenamemodeNULL 或空字符串,这些函数则会触发无效的参数处理程序,如 Parameter Validation。 如果允许执行继续,则这些函数将返回 NULL 并将 errno 设置为 EINVAL

有关详细信息,请参阅errno, _doserrno, _sys_errlist_sys_nerr.

备注

fopen 函数打开由 filename 指定的文件。 默认情况下,使用 ANSI 代码页 (CP_ACP) 解释窄 filename 字符串。 在 Windows 桌面应用程序中,可以通过使用 SetFileApisToOEM 函数将它更改为 OEM 代码页 (CP_OEMCP)。 可以使用 AreFileApisANSI 函数来确定是使用 ANSI 还是系统默认的 OEM 代码页来解释 filename_wfopenfopen 的宽字符版本;_wfopen 参数是宽字符串。 除此以外, _wfopenfopen 的行为完全相同。 仅使用 _wfopen 不会影响在文件流中使用的编码字符集。

fopen 接受执行时在文件系统上有效的路径; fopen 还接受 UNC 路径和包含映射的网络驱动器的路径(前提是执行代码的系统在执行时能够访问共享或映射的驱动器)。 为 fopen 构造路径时,请确保驱动器、路径或网络共享在执行环境中可用。 可使用斜杠 (/) 或反斜杠 (\) 作为路径中的目录分隔符。

对文件执行任何其他操作前,请始终检查返回值以确定指针是否为 NULL。 如果发生错误,系统将设置全局变量 errno,此变量可用于获取特定错误信息。 有关详细信息,请参阅errno, _doserrno, _sys_errlist_sys_nerr.

默认情况下,此函数的全局状态范围限定为应用程序。 若要更改此状态,请参阅 CRT 中的全局状态

Unicode 支持

fopen 支持 Unicode 文件流。 若要打开 Unicode 文件,请将指定所需编码的 ccs=encoding 标志传递到 fopen,如下所示。

FILE *fp = fopen("newfile.txt", "rt+, ccs=UTF-8");

ccs 编码的允许值为 UNICODEUTF-8UTF-16LE

在 Unicode 模式下打开文件时,输入函数会将从文件中读取的数据转换为存储为 wchar_t类型的 UTF-16 数据。 写入到在 Unicode 模式下打开的文件的函数需要包含存储为 wchar_t类型的 UTF-16 数据的缓冲区。 如果将文件编码为 UTF-8,则在写入它时,UTF-16 数据会转换为 UTF-8。 在读取它时,该文件的 UTF-8 编码的内容会转换为 UTF-16。 尝试在 Unicode 模式下读取或写入奇数个字节会导致 参数验证 错误。 若要读取或写入在你的程序中存储为 UTF-8 的数据,请使用文本或二进制文件模式,而不是 Unicode 模式。 你应负责所有必需的编码转换。

如果文件已存在并已打开以进行读取或追加,则文件中的任何字节顺序标记 (BOM)将确定编码。 BOM 编码优先于由 ccs 标志指定的编码。 只有在没有 BOM 或文件是新文件时,才使用 ccs 编码。

注意

BOM 检测仅适用于在 Unicode 模式下(即通过传递 ccs 标志)打开的文件。

下表汇总的模式用于传递到文件中的 ccs 和字节顺序标记的各种 fopen 标志。

基于 ccs 标志和 BOM 使用的编码

ccs 标志 无 BOM(或新文件) BOM:UTF-8 BOM:UTF-16
UNICODE UTF-16LE UTF-8 UTF-16LE
UTF-8 UTF-8 UTF-8 UTF-16LE
UTF-16LE UTF-16LE UTF-8 UTF-16LE

在 Unicode 模式下打开以进行写入的文件将自动写入 BOM。

如果 mode 为某 encoding 值的 a, ccs=encodingfopen 将先尝试使用读取和写入访问权限打开文件。 如果此操作成功,此函数将读取 BOM 以确定文件的编码。 如果失败,此函数将使用文件的默认编码。 在任一情况下,fopen 使用仅写访问权限重新打开文件。 (此行为仅适用于 "a" 模式,不适用于 "a+" 模式。)

一般文本例程映射

TCHAR.H 例程 _UNICODE_MBCS 未定义 _MBCS 已定义 _UNICODE 已定义
_tfopen fopen fopen _wfopen

字符串 mode 指定为文件请求的访问类型,如下所示。

mode Access
"r" 打开以便读取。 如果文件不存在或找不到,fopen 调用将失败。
"w" 打开用于写入的空文件。 如果给定文件存在,则其内容会被销毁。
"a" 在文件末尾打开以进行写入(追加),在新数据写入到文件之前不移除文件末尾 (EOF) 标记。 如果文件不存在,则创建文件。
"r+" 打开以便读取和写入。 文件必须存在。
"w+" 打开用于读取和写入的空文件。 如果文件存在,则其内容会被销毁。
"a+" 打开以进行读取和追加。 追加操作包括在新数据写入文件之前移除 EOF 标记。 写入完成后,EOF 标记不会还原。 如果文件不存在,则创建文件。

使用 "a" 访问类型或 "a+" 访问类型打开文件时,所有写入操作均将在文件末尾进行。 使用 fseekrewind可重新定位文件指针,但在执行任何写入操作前,文件指针将始终被移回文件末尾。 因此,无法覆盖现有数据。

在 EOF 标记追加到文件之前,"a" 模式不会将其移除。 在追加后,MS-DOS TYPE 命令只显示原始 EOF 标记之前的数据,不显示追加到文件的任何数据。 EOF 标记追加到文件之前, "a+" 模式不会将其移除。 在追加后,MS-DOS TYPE 命令显示文件中的所有数据。 需使用 "a+" 模式才能附加到通过 CTRL+Z EOF 标记终止的流文件。

指定 "r+""w+""a+" 访问类型时,允许读取和写入(文件将处于打开状态以进行“更新”)。 但是,当你从读取切换到写入时,输入操作必须遇到 EOF 标记。 如果没有 EOF,必须使用对文件定位函数的干预调用。 文件定位函数是 fsetposfseekrewind。 从写入切换到读取时,必须使用对 fflush 或文件定位函数的干预调用。

除了前面的值以外,可将以下字符追加到 mode 以指定换行符的转换模式。

mode 修饰符 转换模式
t 在文本(转换)模式下打开。 输入时,回车换行 (CR-LF) 组合将转换为单一的换行 (LF);输出时,LF 字符将转换为 CR-LF 组合。 CTRL+Z 也将在输入时解释为文件尾字符。
b 在二进制(未转换)模式下打开;禁止涉及回车和换行字符的转换。

在文本模式下, CTRL+Z 解释为输入上的 EOF 字符。 在使用 "a+"打开以供读取/写入的文件中,fopen 将检查文件末尾的 CTRL+Z ,并删除它(如果可能)。 将其删除是因为使用 fseekftell 在以 CTRL+Z 结尾的文件中移动时,可能导致 fseek 在文件末尾附近错误运行。

在文本模式下,输入时,回车-换行 (CRLF) 组合将转换为单一的换行 (LF) 字符;输出时,LF 字符将转换为 CRLF 组合。 当 Unicode 流 I/O 函数在文本模式(默认设置)下运行时,源或目标流将假定为一系列多字节字符。 因此,Unicode 流输入函数将多字节字符转换为宽字符(就像调用 mbtowc 函数一样)。 出于同一原因,Unicode 流输出函数将宽字符转换为多字节字符(就像调用 wctomb 函数一样)。

如果 tbmode 中未给出,则默认转换模式由全局变量 _fmode 定义。 如果 tb 是该参数的前缀,则函数将失败并返回 NULL

有关如何在 Unicode 和多字节流 I/O 中使用文本和二进制模式的详细信息,请参阅 文本和二进制模式文件 I/O文本和二进制模式下的 Unicode 流 I/O

可将以下选项追加到 mode 以指定更多行为。

mode 修饰符 行为
x 如果 filename 已存在,则强制函数失败。 只能与“w”或“w+”说明符一起使用。
c 启用关联 filename 的提交标志,以便在调用 fflush_flushall 时将文件缓冲区的内容直接写入磁盘。
n 将关联的 filename 的提交标志重置为“no-commit”。此标志为默认值。 如果将程序显式链接到 COMMODE.OBJ,它还将重写全局提交标志。 除非将程序显式链接到 COMMODE.OBJ,否则全局提交标志默认为 "no-commit"(请参阅链接选项)。
N 指定文件不由子进程继承。
S 指定缓存针对(但不限于)从磁盘的顺序访问进行优化。
R 指定缓存针对(但不限于)从磁盘的随机访问进行优化。
T 指定一个文件,除非内存压力需要它,否则不会写入磁盘。
D 指定在关闭最后一个指向该文件的指针时删除的临时文件。
ccs=encoding 指定要用于此文件的编码字符集(UTF-8UTF-16LEUNICODE)。 如果需要 ANSI 编码,请不要指定此字符集。 此标志与前面的标志用逗号 (,) 分隔。 例如:FILE *f = fopen("newfile.txt", "rt+, ccs=UTF-8");

fopen_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(翻译)
x _O_EXCL
c
n
S _O_SEQUENTIAL
R _O_RANDOM
T _O_SHORTLIVED
D _O_TEMPORARY
ccs=UNICODE _O_WTEXT
*ccs=UTF-8* _O_UTF8
ccs=UTF-16LE _O_UTF16

如果你使用 rb 模式,不必移植代码,而如果希望读取大文件中的大部分内容或不担心网络性能,你可能还要考虑是否使用内存映射的 Win32 文件方式。

关于 TD

  • 只要内存压力不需要,T 就避免将文件写入磁盘。 有关详细信息,请参阅文件属性常量中的 FILE_ATTRIBUTE_TEMPORARY,以及此博客文章它只是暂时性的
  • D 指定写入磁盘的常规文件。 区别在于它在关闭时会自动删除。 可以组合 TD 来获取这两种语义。

cnRStTDmode 选项是 fopen_wfopen 的 Microsoft 扩展,不应在需要 ANSI 可移植性时使用。

要求

函数 必需的标头
fopen <stdio.h>
_wfopen <stdio.h><wchar.h>

_wfopen 是 Microsoft 扩展。 有关兼容性的更多信息,请参见 兼容性

cntSRTDmode 选项是 fopen_fdopen 的 Microsoft 扩展,不应在需要 ANSI 可移植性时使用。

示例 1

以下程序打开两个文件。 它使用 fclose 关闭第一个文件,使用 _fcloseall 关闭所有剩余文件。

// crt_fopen.c
// compile with: /W3
// 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 )
{
   int numclosed;

   // Open for read (will fail if file "crt_fopen.c" does not exist)
   if( (stream  = fopen( "crt_fopen.c", "r" )) == NULL ) // C4996
   // Note: fopen is deprecated; consider using fopen_s instead
      printf( "The file 'crt_fopen.c' was not opened\n" );
   else
      printf( "The file 'crt_fopen.c' was opened\n" );

   // Open for write
   if( (stream2 = fopen( "data2", "w+" )) == NULL ) // C4996
      printf( "The file 'data2' was not opened\n" );
   else
      printf( "The file 'data2' was opened\n" );

   // Close stream if it is not NULL
   if( stream)
   {
      if ( fclose( stream ) )
      {
         printf( "The file 'crt_fopen.c' was not closed\n" );
      }
   }

   // All other files are closed:
   numclosed = _fcloseall( );
   printf( "Number of files closed by _fcloseall: %u\n", numclosed );
}
The file 'crt_fopen.c' was opened
The file 'data2' was opened
Number of files closed by _fcloseall: 1

示例 2

以下程序在具有 Unicode 编码的文本模式下创建文件(或在文件存在时覆盖文件)。 然后,它将两个字符串写入文件并关闭文件。 输出是名为 _wfopen_test.xml 的文件,其中包含输出部分中的数据。

// crt__wfopen.c
// compile with: /W3
// This program creates a file (or overwrites one if
// it exists), in text mode using Unicode encoding.
// It then writes two strings into the file
// and then closes the file.

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <wchar.h>

#define BUFFER_SIZE 50

int main(int argc, char** argv)
{
    wchar_t str[BUFFER_SIZE];
    size_t  strSize;
    FILE*   fileHandle;

    // Create an the xml file in text and Unicode encoding mode.
    if ((fileHandle = _wfopen( L"_wfopen_test.xml",L"wt+,ccs=UNICODE")) == NULL) // C4996
    // Note: _wfopen is deprecated; consider using _wfopen_s instead
    {
        wprintf(L"_wfopen failed!\n");
        return(0);
    }

    // Write a string into the file.
    wcscpy_s(str, sizeof(str)/sizeof(wchar_t), L"<xmlTag>\n");
    strSize = wcslen(str);
    if (fwrite(str, sizeof(wchar_t), strSize, fileHandle) != strSize)
    {
        wprintf(L"fwrite failed!\n");
    }

    // Write a string into the file.
    wcscpy_s(str, sizeof(str)/sizeof(wchar_t), L"</xmlTag>");
    strSize = wcslen(str);
    if (fwrite(str, sizeof(wchar_t), strSize, fileHandle) != strSize)
    {
        wprintf(L"fwrite failed!\n");
    }

    // Close the file.
    if (fclose(fileHandle))
    {
        wprintf(L"fclose failed!\n");
    }
    return 0;
}

另请参阅

流 I/O
多字节字符序列的解释
fclose_fcloseall
_fdopen_wfdopen
ferror
_fileno
freopen_wfreopen
_open_wopen
_setmode
_sopen_wsopen