FILE *fopen( const char *filename, // ファイル名 const char *mode // 許可するアクセスの種類 );fopen、_wfopen | MSDN
fopenの代わりに、セキュリティが強化されたfopen_sを使うことが推奨されています。
errno_t fopen_s( FILE **pFile, // 開かれたファイルポインタを受け取るポインタ const char *filename, // ファイル名 const char *mode // 許可するアクセスの種類 );fopen_s、_wfopen_s | MSDN
ただしfopen_sで開いたファイルは共有できないため、その必要があるときには_fsopenを用います。Remarks - fopen_s, _wfopen_s | Microsoft Learn
文字列 | ||||
---|---|---|---|---|
読み取り | 書き込み | ファイルが存在しない | ファイルが存在する | |
r | ○ | × | 呼び出しに失敗 | そのファイルから読み込み |
r+ | ○ | ○ | ||
w | × | ○ | ファイルを作成 | その内容を破棄して、書き込み (上書き) |
w+ | ○ | ○ | ||
a | × | ○ | ファイルを作成 | EOFを削除せずに、末尾に書き込み |
a+ | ○ | ○ | EOFを削除して、末尾に書き込み |
文字列 | 機能 |
---|---|
t | テキスト モード。キャリッジリターンとラインフィードを、変換する |
b | バイナリ モード。キャリッジリターンとラインフィードを、変換しない |
c | コミット フラグを有効 |
n | コミット フラグをリセット |
N | 子プロセスに継承されないように指定 |
S | キャッシュを、シーケンシャルアクセスに最適化 |
R | キャッシュを、ランダム アクセスに最適化 |
T | 一時ファイルとして指定。可能ならば、ディスクに書き込まれない |
D | 一時ファイルとして指定。ディスクに書き込まれない |
これらの関数の違いはエラーコードの取得方法にあります。fopenでは戻り値がNULLであることからエラーの発生を検知し、errnoマクロからエラーコードを取得します。一方でfopen_sでは戻り値でエラーコードが返され、それが0ではないことでエラーを検知できます。
FILE* stream;
int errorCode;
if (NULL == (stream = fopen("sample.txt", "r")))
{
// エラー発生
errorCode = errno;
}
FILE* stream;
errno_t errorCode;
if (0 != (errorCode = fopen_s(&stream, "sample.txt", "r")))
{
// エラー発生
}
オープン時にファイル共有の方法を指定できます。
FILE *_fsopen( const char *filename, const char *mode, int shflag );_fsopen、_wfsopen | MSDN
定数 | 読み取り | 書き込み |
---|---|---|
_SH_DENYNO | ○ | ○ |
_SH_DENYRD (ReaD) | × | ○ |
_SH_DENYRW (ReadWrite) | × | × |
_SH_DENYWR (WRite) | ○ | × |
開いたファイルは必ず閉じます。特に書き込んだときに閉じないと、バッファ内のデータが書き込まれません。
int fclose( FILE *stream );
int _fcloseall( void );fclose、_fcloseall | MSDN
int fflush( FILE *stream );fflush | MSDN
ストリームをフラッシュできます。バッファが空か読み取り専用モードのときは、何も作用しません。
次のsetvbuf関数でバッファを無効にすることで、フラッシュを不要にできます。
ストリームのバッファサイズは既定で4kですが、これは次の関数で変更できます。
int setvbuf( FILE *stream, // FILE 構造体へのポインタ char *buffer, // ユーザーが割り当てたバッファー int mode, // バッファリングのモード size_t size // バッファー サイズ [バイト単位] );setvbuf | MSDN
値 | |
---|---|
_IOFBF | フル バッファリング (Full buffering) |
_IOLBF | 行バッファリング (Line buffering) |
_IONBF | バッファリングなし (No buffering) |
char buf[1024];
if (setvbuf(stream, buf, _IOFBF, sizeof(buf)) != 0)
{
// 失敗
}
// バッファを無効にする
setvbuf(stream, NULL, _IONBF, 0);
void rewind(
FILE *stream //
);
rewind | MSDN
int fseek( FILE *stream, // long offset, // int origin // );fseek、_fseeki64 | MSDN
rewind()は、fseek()で
fseek(stream, 0L, SEEK_SET);
と呼び出すことと同義です。ただしrewind()では成功したかどうかは確認できず、呼び出し時にはエラー インジケーターがクリアされます。
long ftell(
FILE *stream // FILE 構造体へのポインタ
);
ftell、_ftelli64 | MSDN
int fputc( int c, // 書き込む文字 FILE *stream // FILE 構造体へのポインタ );fputc、fputwc | MSDN
int fputs( const char *str, // 書き込む文字列 FILE *stream // FILE 構造体へのポインタ );fputs、fputws | MSDN
size_t fwrite( const void *buffer, // 書き込むデータへのポインタ size_t size, // 項目サイズ (バイト単位) size_t count, // 書き込む項目の最大数 FILE *stream // FILE 構造体へのポインタ );fwrite | MSDN
int fprintf( FILE *stream, // FILE 構造体へのポインタ const char *format [, // 書式指定文字列 argument ]... // 省略可能な引数 );fprintf、_fprintf_l、fwprintf、_fwprintf_l | MSDN
これらの関数は、それぞれ次の値を返します。
FILE* stream; errno_t errorCode = fopen_s(&stream, "sample.txt", "w"); if (errorCode != 0) { // error } else { int character = fputc('a', stream); // 97が返される int code = fputs("123", stream); // 0が返される char str[] = "ABC"; size_t size1 = fwrite(str, sizeof(*str), sizeof(str) / sizeof(*str), stream); // 4が返される short num[] = { 1,2,3 }; size_t size2 = fwrite(num, sizeof(*num), sizeof(num) / sizeof(*num), stream); // 3が返される char word[] = "Hello"; int byte = fprintf(stream, "%s", word); // 5が返される if (fclose(stream) != 0) { // error } }
データを読み込む関数も複数ありますが、これらは読み込むデータサイズが異なります。
また、戻り値も異なります。
1文字読み込めます。
int fgetc(
FILE *stream // FILE 構造体へのポインタ
);
fgetc、fgetwc | MSDN
int c = fgetc(stream);
ファイルの内容をすべて読み込むには、EOFが返されるまでfgetc()をくり返し呼びます。
FILE* stream; errno_t errorCode; if (0 == (errorCode = fopen_s(&stream, "sample.txt", "r"))) { int c; while (EOF != (c = fgetc(stream))) { fputc(c, stdout); } fclose(stream); }
1行分読み込めます。厳密には、次のいずれかの条件を満たすまで読みます。
char *fgets( char *str, // データの格納場所 int n, // 読み込む最大文字数 FILE *stream // FILE 構造体へのポインタ );fgets、fgetws | MSDN
fgets()では末尾に必ずNULLが付加されるため、読み込まれる最大文字数はn-1となります。
char buffer[10];
if (NULL == fgets(buffer, 10, stream))
{
// error
}
size_t fread( void *buffer, // データの格納場所 size_t size, // 項目のバイト単位のサイズ size_t count, // 読み込む項目の最大数 FILE *stream // FILE 構造体へのポインタ );fread | MSDN
fread()のcountは読み込む最大数であり、ファイルの末尾に達するかエラーが発生した場合には、実際に読み込まれるのはそれより少なくなります。実際に読み込まれた項目数は、戻り値で確認できます。
char buffer[10];
size_t size1 = fread(buffer, sizeof(*buffer), 10, stream);
// バッファの容量分だけ読み込む
size_t size2 = fread(buffer, sizeof(*buffer), sizeof(buffer) / sizeof(*buffer), stream);
int fscanf( FILE *stream, // FILE 構造体へのポインタ const char *format [, // 書式指定文字列 argument ]... // 省略可能な引数 );fscanf、_fscanf_l、fwscanf、_fwscanf_l | MSDN
fscanf()には、バッファオーバーフローを防ぐ機能が追加されたfscanf_s()があります。
int fscanf_s( FILE *stream, // FILE 構造体へのポインタ const char *format [, // 書式指定文字列 argument ]... // 省略可能な引数 );fscanf_s、_fscanf_s_l、fwscanf_s、_fwscanf_s_l | MSDN
一見すると引数がfscanf()と同じですが、書式指定に文字列を含む場合に違いがあります。たとえばVisual C++で次のように記述すると、
char buffer[10]; fscanf_s(stream, "%s", buffer);
コンパイラは次のように警告してきます。
warning C4473: 'fscanf_s': 書式文字列として渡された引数が不足しています note: プレースホルダーとそのパラメーターには 2 の可変個引数が必要ですが、1 が指定されています。 note: 不足している可変個引数 2 が書式文字列 '%s' に必要です note: この引数はバッファー サイズとして使用されます
これに対処するには文字列を受け取る書式指定の後に、そのバッファのサイズを与えます。c++ - fscanf / fscanf_s difference in behaviour - Stack Overflow
fscanf_s(stream, "%s", buffer, _countof(buffer));
複数の変数を受け取る場合には、次のように記述します。
char buffer[10]; int x[10]; fscanf_s(stream, "%s%d", buffer, _countof(buffer), x);
読み込んだ結果EOFが返されたとしても、それだけでは
のいずれの状況なのか判断できません。
バイナリデータをテキストモードで読み込んだ場合には、終端でもエラーでもない状況でEOF (-1) が返されることがあります。これに対処するにはファイルのオープン時にモードに"b"を追記し、バイナリモードとします。
ファイルの終端か否かを判断できます。
int feof(
FILE *stream // FILE 構造体へのポインタ
);
feof | MSDN
ファイルポインタがファイルの終端を越えているならば0以外、さもなくば0が返されます。
feof()だけでループさせてはなりません。feof()は終端を越えた後に0以外を返すため、終端に達した時点を判定できません。またファイルポインタの取得に失敗した場合には、終端ではないときと同様に0が返されるため、無限ループとなってしまいます。c - Why is “while ( !feof (file) )” always wrong? - Stack Overflow
while (!feof(stream)) // streamが無効ならば、ループは終わらない { fgetc(stream); // 必ず1バイト余計に読み取ってしまう ... }
int ferror(
FILE *stream // FILE 構造体へのポインタ
);
ferror | MSDN
エラーが発生しているならば0以外、さもなくば0が返されます。
int _stat(
const char *path, // ファイルパス
struct _stat *buffer
);
_stat、_stat32、_stat64、_stati64、_stat32i64、_stat64i32、_wstat、_wstat32、_wstat64、_wstati64、_wstat32i64、_wstat64i32 | MSDN
すでに開いているファイルを対象とするならば、_fstat()を用います。
int _fstat(
int fd, // 開いているファイルのファイル記述子
struct _stat *buffer
);
_fstat、_fstat32、_fstat64、_fstati64、_fstat32i64、_fstat64i32 | MSDN
メンバ | 内容 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
st_gid | Numeric identifier of group that owns the file (UNIX-specific) This field will always be zero on Windows systems. A redirected file is classified as a Windows file. | ||||||||||||||||
st_atime | Time of last access of file. Valid on NTFS but not on FAT formatted disk drives. | ||||||||||||||||
st_ctime | Time of creation of file. Valid on NTFS but not on FAT formatted disk drives. | ||||||||||||||||
st_dev | Drive number of the disk containing the file (same as st_rdev). | ||||||||||||||||
st_ino | Number of the information node (the inode) for the file (UNIX-specific). On UNIX file systems, the inode describes the file date and time stamps, permissions, and content. When files are hard-linked to one another, they share the same inode. The inode, and therefore st_ino, has no meaning in the FAT, HPFS, or NTFS file systems. | ||||||||||||||||
st_mode | ファイルモード情報のビットマスク
|
||||||||||||||||
st_mtime | Time of last modification of file. | ||||||||||||||||
st_nlink | Always 1 on non-NTFS file systems. | ||||||||||||||||
st_rdev | Drive number of the disk containing the file (same as st_dev). | ||||||||||||||||
st_size | Size of the file in bytes; a 64-bit integer for variations with the i64 suffix. | ||||||||||||||||
st_uid | Numeric identifier of user who owns file (UNIX-specific). This field will always be zero on Windows systems. A redirected file is classified as a Windows file. |
struct stat buf; if (stat("sample.txt", &buf) == 0) { unsigned short mode = buf.st_mode; long size = buf.st_size; }
stat()によりファイルの情報を取得できたときに、それが存在していると判定できます。Fastest way to check if a file exist using standard C++/C++11/C? - Stack Overflow
この関数はロックが原因で開けないときでも、0を返します。
struct stat buf; if (stat("sample.txt", &buf) == 0) { // 存在している } else { // 存在していない }
void _splitpath( const char *path, // 完全パス char *drive, // ドライブ文字 char *dir, // ディレクトリ パス char *fname, // ファイル名 (拡張子なし) char *ext // ファイル名の拡張子 );_splitpath、_wsplitpath | MSDN
分解するパスをpathで渡すと、分解されたパスがそれ以外の引数で返されます。結果として不要な要素にはNULLを渡します。
char path[] = "C:\\a\\b\\c.txt"; char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; _splitpath(path, drive, dir, fname, ext); // drive : "C:" // dir : "\\a\\b\\" // fname : "c" // ext : ".txt"
FILE *freopen( const char *path, // 新しいファイル パス const char *mode, // アクセス許可の種類 FILE *stream // 割り当て元のファイルへのポインタ );freopen、_wfreopen | MSDN
freopen()はpathのファイルを開き、そのポインタをstreamへ割り当てます。そして開いたファイルへのポインタを返します。
たとえばstderrへの出力をファイルへリダイレクトするには、次のようにします。
FILE* stream = freopen("err.txt", "w", stderr);
int _pipe( int *pfds, // 読み書きファイル記述子を格納する配列 unsigned int psize, // パイプのために予約するメモリ量 [バイト単位] int textmode // ファイルモード );_pipe | MSDN
2つの要素を持った配列pfdsを渡すと、_pipe()はそれに
を割り当てます。
psizeで十分なメモリを確保しないと、パイプを使用した読み書き時に待機し続けることになります。
textmodeでは変換モードを指定します。0と指定した場合は、既定で_O_TEXTとなります。
#define O_TEXT _O_TEXT #define O_BINARY _O_BINARY #define _O_TEXT 0x4000 // file mode is text (translated) #define _O_BINARY 0x8000 // file mode is binary (untranslated)ucrt\fcntl.h
int _dup(
int fd // 開いているファイルを参照するファイル記述子
);
fdのコピーが作成され、それが返されます。
int _dup2( int fd1, // 開いているファイルを参照するファイル記述子 int fd2 // 任意のファイル記述子 );_dup、_dup2 | MSDN
fd1のコピーが作成され、それがfd2に割り当てられます。
エラーが発生した場合には、各関数とも-1を返します。
#define BUFFER_SIZE 256 int pfds[2]; _pipe(pfds, BUFFER_SIZE, O_BINARY); _dup2(pfds[0], _fileno(stdin)); // 読み取り記述子のコピーを作成し、それを標準入力へ割り当てる _dup2(pfds[1], _fileno(stdout)); // 書き込み記述子のコピーを作成し、それを標準出力へ割り当てる setvbuf(stdout, NULL, _IONBF, 0); // バッファを無効にする fprintf(stdout, "123456789"); // 標準出力への出力を、標準入力へパイプする char buffer[BUFFER_SIZE] = {}; fread(buffer, sizeof(*buffer), 5, stdin); _close(pfds[0]); _close(pfds[1]);
FILE* stream = fopen("sample.txt", "r");
// ファイルストリームのコピーを作成し、それを標準入力へ割り当てる
_dup2(_fileno(stream), _fileno(stdin));
ファイルを示すオブジェクトには、
がありますが、これらはそれぞれ変換できます。
変換元 → 変換先 | 関数 |
---|---|
ファイル記述子 → FILE構造体 |
FILE *_fdopen( int fd, // 開いているファイルの、ファイル記述子 const char *mode // ファイルアクセスの種類 );_fdopen、_wfdopen | MSDN |
FILE構造体 → ファイル記述子 |
int _fileno(
FILE *stream // FILE 構造体へのポインタ
);
_fileno | MSDN
|
ファイル記述子 → ファイル ハンドル |
intptr_t _get_osfhandle(
int fd // 既存のファイル記述子
);
_get_osfhandle | MSDN
|
ファイル ハンドル → ファイル記述子 |
int _open_osfhandle ( intptr_t osfhandle, // OSのファイル ハンドル int flags // 許可される演算の種類 );_open_osfhandle | MSDN |