C言語でファイル操作する方法~ハッカーのたしなみ

523, 2022-07-27

目次

C言語でファイル操作する方法~ハッカーのたしなみ

C言語……。
ハッカーご用達のスーパー言語……。

この言語を操るものはハッカーにもっとも近づける存在になれる……。

おやおや、今日もハッカーの卵がこのページを開きましたね。
ようこそ、ハッカー。

C言語を操るものにとってファイル操作は基本中の基本……。
ハッカーのたしなみのようなものです。

この基礎教養を身につけられるようにこの記事はそのヒントを提供しましょう……。
進め、未来のハッカーよ。
汝(なんじ)の道をさえぎるものはない。

関連記事

ファイルを開く

さて、まずは基本中の基本。
テーブルマナーで言うところのスプーンの取り方に相当する基礎。

それはファイルを開くこと。
まずあなたはファイルを開かねばなりません。

ファイルを開いてあんなことやこんなことをする。
まぁなんて大胆な……。

しかしそれも始まりはファイルを開くことからです。
便利な関数を紹介しましょう。

#include <stdio.h>

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

fopen()関数は指定したファイル名のファイルを指定のモードで開く関数です。
モードは↓があります。

  • r ... テキストファイルを読み込みモードで開く

  • rb ... バイナリファイルを読み込みモードで開く

  • w ... テキストファイルを書き込みモードで開きファイルを空にする

  • wb ... バイナリファイルを書き込みモードで開きファイルを空にする

  • a ... テキストファイルを追記モードで開く(ファイルが無い場合は新規作成)

  • ab ... バイナリファイルを追記モードで開く(ファイルが無い場合は新規作成)

  • r+ ... テキストファイルを読み込み/書き込みモードで開く

  • rb+ ... バイナリファイルを読み込み/書き込みモードで開く

  • w+ ... テキストファイルを読み込み/書き込みモードで開く(ファイルを空にする)

  • wb+ ... バイナリファイルを読み込み/書き込みモードで開く(ファイルを空にする)

  • a+ ... テキストファイルを読み込み/書き込みモードで開く(ファイルが無い場合は新規作成)

  • ab+ ... バイナリファイルを読み込み/書き込みモードで開く(ファイルが無い場合は新規作成)

なんてモードの数だ。
C言語のfopen()はバケモノか……!

もっともよく使うのはr, w, aのいずれかです。
最初はこれだけ押さえておけばOKです。

fopen()は実際には↓のように使います。

// ファイルを開く
FILE *fin = fopen("myfile.txt", "r");
if (fin == NULL) {
    perror("fopen");
    exit(1);
}

fopen()はファイルを開くのに失敗するとNULLを返しerrnoを適切にセットします。
ですのでfopen()がNULLを返して来たらperror()などでerrnoを参照します。

ファイルを閉じる

力のある者は力のない者を助けなければいけません。
それが力のある者の責務です。

それと同じでファイルも開いたら閉じなければいけません。
それがファイルを開いたものの責務です。

開いたファイルを閉じないとメモリリークというバグになります。
ですのでファイルは開いたら必ず閉じるようにしましょう。

ファイルを閉じるには↓の関数が使えます。

#include <stdio.h>

int fclose(FILE *stream);

ファイルを開いたらちゃんと閉じる。
そのようなコードは↓のように書きます。

// ファイルを開く
FILE *fin = fopen("myfile.txt", "r");
if (fin == NULL) {
    perror("fopen");
    exit(1);
}

// ファイルを閉じる
fclose(fin);

ファイルから1文字読み込む

ファイルから1文字読み込む。
これは色々なシーンで使います。

↓はファイルから1文字ずつ読み込んでファイル内容を表示するプログラムのサンプルです。

#include <stdio.h>

int main(void) {
    FILE *fin = fopen("myfile.txt", "r");
    if (fin == NULL) {
        perror("fopen");
        exit(1);
    }

    for (;;) {
        int c = fgetc(fin);  // 1文字読み込む
        if (c == EOF) {
            break;
        }

        putchar(c);  // 1文字出力
    }

    fclose(fin);
    return 0;
}

fgetc()は引数のファイルから1文字ずつ読み込みます。
fgetc()は読み込みが進んでファイル終端に達したらEOF定数を返します。

↑のコードはfgetc()でファイル内容をすべて読み込むテンプレ的なコード……。
あなたのスニペットに加えてください……。

#include <stdio.h>

int fgetc(FILE *stream);

ファイルから1行読み込む

テキストファイルから1行読み込む。
1文字、そして1行という処理の単位はファイル操作では一般的です。

C言語にはfgets()という便利な行読み込み関数があります。
これを使いましょう……。

#include <stdio.h>

char *fgets(char *s, int size, FILE *stream);

サンプルコードをご覧あれ!!

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

int main(void) {
    FILE *fin = fopen("myfile.txt", "r");
    if (fin == NULL) {
        perror("fopen");
        exit(1);
    }

    // ファイルから1行ずつ読み込む
    char line[100];
    for (; fgets(line, sizeof line, fin); ) {
        printf("%s", line);  // 1行出力
    }

    fclose(fin);
    return 0;
}

fgets()の第1引数にはバッファ、第2引数にはバッファサイズ、第3引数にはファイルオブジェクトを渡します。
fgets()は読み込みに失敗したかまたはファイル終端に達するとNULLを返します。
ですのでこれを利用してループ文で↑のようにファイルの行をすべて読み込んでいくことができます。

ファイル内容をすべて読み込む

1文字とか1行とかまどろっこしい!
朕はすべてを欲しているぞ!

そういう場合はファイル内容をすべて読み込む処理を書きたいわけです。
その場合は↓のようなコードを書きます。

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

/**
 * ファイル内容をすべて読み込み動的メモリ確保した文字列のポインタを返す
 *
 * @param[in] fname ファイル名
 * @return 成功したら文字列のポインタ。失敗したらNULL
 */
char *read_file(const char *fname) {
    FILE *fin = fopen(fname, "r+");  // ファイルを読み書きモードで開く
    if (fin == NULL) {
        return NULL;
    }

    fseek(fin, 0, SEEK_END);  // ファイルポインタをファイル末尾に
    long size = ftell(fin);  // 現在のポジションをバイト数で取得
    fseek(fin, 0, SEEK_SET);  // ファイルポインタをファイル先頭に戻す

    long fullsize = size + sizeof(char);  // サイズにナル文字分を加える
    char *dst = malloc(fullsize);  // 動的メモリ確保
    if (dst == NULL) {
        fclose(fin);
        return NULL;
    }

    fread(dst, sizeof(char), size, fin);  // ファイル内容をすべて読み込む
    dst[size] = '\0';  // 文字列にナル文字を加える

    fclose(fin);  // ファイルを閉じる
    return dst;
}

int main(void) {
    // ファイルを読み込む
    char *content = read_file("myfile.txt");
    if (content == NULL) {
        perror("read_file");
        return 1;
    }

    // ファイル内容を出力
    printf("%s", content);

    // メモリを解放
    free(content);
    return 0;
}

↑の関数read_file()は指定のファイル名のファイル内容をすべて読み込み、動的メモリ確保した文字列にその内容を保存します。
そして返り値でその動的メモリ確保した文字列を返します。

この関数は便利なのであなたのツールに加えてみてください……。

ファイルへの書き込みは?

ファイルへの書き込みは↓の関数が使えます。

  • fputc() ... 1文字書き込む

  • fputs() ... 1行(改行含めず)書き込む

  • fprintf() ... フォーマットで書き込む

今回はこれらの関数の使い方は省略します……。
またモチベが上がったら追記しますね……。

(^ _ ^)

モチベが足りない!

おわりに

今回はC言語のファイル操作について解説しました。
ハッカーたるものファイル操作は寝言でも出来るようにしておかないといけません。
来たれハッカー、決戦の日は近い……。

(^ _ ^)

スーパーハカー!

(・ v ・)

君が世界を変えるんだ



この記事のアンケートを送信する