C言語基礎|ファイルのオープン

「ファイルは“開いてから”がスタート! fopen で入出力の扉を開けよう。」

ノートを使うときって、まず表紙を開きますよね。開かないと読めないし、書けない。
C言語のファイル処理もまったく同じで、**最初にファイルを開く(オープンする)**ところから始まります。

この「開く」を担当するのが fopen 関数です。
fopen は、ファイルとストリームを結びつけて、以後の読み書きに使う通り道(ストリーム)を準備してくれます。
そしてその通り道を操作するための“取っ手”として、FILE
(FILE型へのポインタ)を返します。

まず押さえる要点(超重要)

  • ファイルを使うときは、まず fopen でオープンする
  • fopen は成功すると FILE* を返す
  • 失敗すると NULL を返す(つまり「どこも指していないポインタ」)

図でつかむ:fopen がやっていること

図:ファイル名とモードを渡して、ストリーム(fp)を受け取る

図の説明

  • 第1引数の「ファイル名」で、どのファイルを扱うか決めます。
  • 第2引数の「モード」で、読みたいのか/書きたいのか/追記したいのか…を決めます。
  • fopen が内部でストリームを用意して、制御に必要な情報を FILE 型として管理し、その場所を指す FILE* を返してくれます。
  • 以後はこの fp を使って、読み書きの関数に「このファイルに対してやってね」と指示します。

サンプルプログラム

メモ用ファイル memo.txt に1行だけ追記するシンプルなプログラム例です。
「追記(a)」モードを使うと、既存の内容を壊さず末尾に追加できます。

プロジェクト名:chap13-2-1 ソースファイル名:chap13-2-1.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

Windows の Visual Studio が実行環境の場合、以下のパスに「memo.txt」が作成されます。
C:\Users\<ユーザー名>\source\repos\chap13-2-1\chap13-2-1

#include <windows.h>
#include <stdio.h>

int main(void)
{
    SetConsoleOutputCP(65001); // 出力をUTF-8に設定
    FILE *fp;

    fp = fopen("memo.txt", "a");
    if (fp == NULL) {
        fprintf(stderr, "ファイルを開けませんでした。保存先を確認してください。\n");
        return 1;
    }

    fprintf(fp, "今日はファイル入門を進めた!\n");
    fclose(fp);

    printf("メモを書き込みました。\n");
    return 0;
}

このプログラムで起きている流れ(文章で説明)

  • fopen("memo.txt", "a") で memo.txt を「追記モード」で開きます。
  • fp が NULL ならオープン失敗なので、stderr にエラーメッセージを出して終了します。
  • 成功したら fprintf(fp, ...) で fp に結び付いたストリームへ文字列を流し込み、結果としてファイル末尾に追記されます
  • 最後に fclose(fp) でファイルを閉じます(開いたら閉じる、が基本です)
  • 仕上げに stdout へ完了メッセージを出します。

fopen の書式と引数をやさしく分解

書式

項目内容
ヘッダ#include <stdio.h>
形式FILE *fopen(const char *filename, const char *mode);
役割filename のファイルを mode の指定で開き、ストリームに結び付ける
返り値成功:FILE* / 失敗:NULL

表の説明

  • FILE* は「このストリーム(このファイル操作の窓口)を使ってね」というハンドル(取っ手)です。
  • filename と mode は文字列(char の並び)で渡します。
  • 失敗時は NULL なので、必ず if (fp == NULL) のチェックを入れるのが安全です。

モードってなに?(読み方を表で整理)

モードは「どう開くか」の指定です。まずは頻出のものから覚えるとラクです。

代表的なモードの意味(テキスト / バイナリ)

モード種類主な用途ポイント
rテキスト読み取りファイルが存在しないと失敗しやすい
wテキスト書き込み(新規作成/上書き)既存内容は消えて0からになる
aテキスト追記書き込みは常に末尾に追加される
rbバイナリ読み取りバイナリとして読む
wbバイナリ書き込み(新規作成/上書き)バイナリとして書く
abバイナリ追記バイナリ末尾へ追加

表の説明(ここがイメージのコツ)

  • r は「読むだけ」。存在しないと読めないので失敗しやすいです。
  • w は「書くために用意する」。既にあれば中身を消して作り直す、と思うと安全です。
  • a は「末尾に足す」。ログやメモにぴったりです。
  • b が付くと「バイナリ扱い」。本節はテキスト中心なので、まずは r / w / a を押さえればOKです。

更新モード(+)の考え方:読み書き両方やりたいとき

  • を付けると「更新(読取りと書込み)」になります。

表:+ が付くモードの概要

モードできること注意点(重要)
r+既存ファイルを読み書き存在しないと基本失敗
w+読み書き(新規/上書き)中身は0からになる
a+読み書き(追記ベース)書き込みは末尾に寄りやすい

表の説明(なぜ注意が必要?)
更新モードでは「読み」と「書き」を交互にやりがちです。
このとき、処理系のルールとして 読み→書き書き→読み の切り替えの間に、ファイル位置を調整する関数(fseek / rewind など)を挟まないと、期待通り動かないことがあります。
最初は無理に混ぜず、読むだけ / 書くだけ / 追記だけで慣れていくのが安心です。

追加モード(a)の“末尾固定”を図で確認

追加モードは「いつ書いても末尾に付く」という性質が大事です。

図:a で開いたファイルは書き込み位置が末尾へ

図の説明

  • a モードで開いた場合、途中に移動して書こうとしても、最終的に末尾に追加される動きになります。
  • ログ追記に向いている一方で、「途中を上書きしたい」用途には向きません。

NULL が返るとはどういうこと?

fopen に失敗すると NULL が返ります。これは「有効なストリームを指していない」という意味です。

図:成功と失敗の違い

図の説明

  • fp が NULL のまま fprintf(fp, ...) のように使うと危険です(未定義動作につながります)。
  • なので「開けたかどうかの確認」は、ファイル処理の基本の基本です。

fopen まわりでよく出てくる“登場人物”まとめ

ファイルオープン周辺の用語と役割

用語役割ひとことで
ファイル名対象のファイルを指定どれを開く?
モード開き方を指定読む?書く?追記?
ストリームデータの流れ道文字が流れる川
FILEストリーム管理情報の型状態を持つ管理票
FILE*FILE を指すポインタ操作用ハンドル
NULL“無効”を表す失敗の合図

表の説明

  • FILE は中身(実装)は処理系依存でも、役割は「管理情報」だと思ってOKです。
  • 私たちは FILE* を通して、その管理情報+ストリームに指示を出していきます。

ひとことアドバイス(習慣にすると強い)

  • fopen の直後は fp == NULL を必ずチェック
  • 開いたら最後は fclose(開けっぱなしにしない)
  • まずは r / w / a の3つを確実にしてから + に挑戦