FrontPage

ファイルの入出力2

UNIX上でテキストファイルのコピーを行う実験プログラム。

制約

コピーするのに1行単位、または1文字単位で読書きするような方法をとらず、必ず1処理で終わらせること。
移植性を高めるためにシステムコールは使用禁止とする。

システムコール以外のファイルサイズ取得にstat()があるが、stat関数はWindows環境でも機能する。(statは使用可)

さらによい方法が見つかれば更新します。

#include <stdio.h>                              /*                                        */
#include <sys/stat.h>                           /* for stat()                             */
/*#include <sys/types.h>                           for stat()                             */
/*#include <unistd.h>                              for stat() * 環境によってない場合がある*/
#include <string.h>                             /* for strchr()                           */
#include <stdlib.h>                             /* for malloc()                           */
                                                /*                                        */
#define MAX_F_NAME 40                           /*                                        */
#define INDEX_OK 0                              /*                                        */
#define RET_OK 0                                /*                                        */
#define RET_NG -1                               /*                                        */
#define FILE_NG -2                              /*                                        */
                                                /*                                        */
int main(void)                                  /*                                        */
{                                               /*                                        */
    FILE *fin;                                  /* 入力元ファイルポインタ                 */
    FILE *fout;                                 /* 出力先ファイルポインタ                 */
    int index = INDEX_OK;                       /* 異常判定                               */
    int rtnCode = RET_OK;                       /* リターンコード                         */
    char fileName[MAX_F_NAME] = "";             /* ファイル名                             */
    char *desk;                                 /* メモリ作業領域                         */
    char ans[3] = "";                           /* 継続判定                               */
    char spew = '\0';                           /* stdin吐出し                            */
    struct stat st;                             /* for stat()                             */
                                                /*                                        */
    while(1)                                    /* 無限ループ                             */
    {                                           /*                                        */
        printf("コピー元ファイル名 > ");        /* 画面表示                               */
        fgets(fileName, MAX_F_NAME, stdin);     /* 入力元ファイル名の取得                 */
        if(!strchr(fileName, '\n'))             /* 入力判定                               */
        {                                       /* 入力が長すぎる                         */
            while(spew != '\n')                 /* stdin吐出し                            */
            {                                   /*                                        */
                spew = fgetc(stdin);            /*                                        */
            }                                   /*                                        */
            spew = '\0';                        /*                                        */
        }                                       /*                                        */
                                                /*                                        */
        fileName[strlen(fileName) - 1] = '\0';  /* 末尾改行の処理                         */
        index = stat(fileName, &st);            /* システム情報取得                       */
        if(INDEX_OK != index)                   /* 異常処理                               */
        {                                       /*                                        */
            printf("statまたは入力のエラー\n"); /* 画面表示                               */
            rtnCode = RET_NG;                   /* リターンコードにエラー設定             */
            break;                              /* 処理終了                               */
        }                                       /*                                        */
                                                /*                                        */
        desk = (char*)malloc(st.st_size);       /* 作業領域の確保                         */
        if(NULL == desk)                        /* 異常処理                               */
        {                                       /*                                        */
            printf("mallocでエラー\n");         /* 画面表示                               */
            rtnCode = RET_NG;                   /* リターンコードにエラー設定             */
            break;                              /* 処理終了                               */
        }                                       /*                                        */
/*      free(desk);*/                           /* * freeするタイミング?                 */
                                                /*                                        */
        fin = fopen(fileName, "rb");            /* 入力元ファイルオープン(バイナリ)       */
        if(NULL == fin)                         /* 異常処理                               */
        {                                       /*                                        */
            printf("fopenでエラー(入力元)\n");  /* 画面表示                               */
            rtnCode = FILE_NG;                  /* リターンコードにファイルエラー設定     */
            break;                              /* 処理終了                               */
        }                                       /*                                        */
                                                /*                                        */
/*      fgets(desk, st.st_size, fin);              * バイナリモードなら一発可能?不可能! */
        fread(desk, sizeof(char), st.st_size, fin); /* これならいける!                   */
        fclose(fin);                            /* 入力元ファイルクローズ                 */
/*      free(desk);*/                           /* * freeするタイミング?                 */
                                                /*                                        */
        printf("コピー先ファイル名 > ");        /* 画面表示                               */
        fgets(fileName, MAX_F_NAME, stdin);     /* 出力先ファイル名の取得                 */
        if(!strchr(fileName, '\n'))             /* 入力判定                               */
        {                                       /* 入力が長すぎる                         */
            while(spew != '\n')                 /* stdin吐出し                            */
            {                                   /*                                        */
                spew = fgetc(stdin);            /*                                        */
            }                                   /*                                        */
            spew = '\0';                        /*                                        */
        }                                       /*                                        */
                                                /*                                        */
        fileName[strlen(fileName) - 1] = '\0';  /* 末尾改行の処理                         */
        fout = fopen(fileName, "ab");           /* 出力先ファイルオープン(バイナリ)       */
        if(NULL == fout)                        /* 異常処理                               */
        {                                       /*                                        */
            printf("fopenでエラー(出力先)\n");  /* 画面表示                               */
            rtnCode = FILE_NG;                  /* リターンコードにファイルエラー設定     */
            break;                              /* 処理終了                               */
        }                                       /*                                        */
                                                /*                                        */
/*      fputs(desk, fout);                         * バイナリモードなら一発可能?不可能! */
        fwrite(desk, sizeof(char), st.st_size, fout); /* これならいける!                 */
        fclose(fout);                           /* 出力先ファイルクローズ                 */
        free(desk);                             /* * freeするタイミング?                 */
                                                /*                                        */
        printf("コピー成功したかも。まだやる?[Y/n] > "); /* 画面表示                     */
        fgets(ans, 2, stdin);                   /* 継続判定の取得                         */
        if(!strchr(ans, '\n'))                  /* 入力判定                               */
        {                                       /* 入力が長すぎる                         */
            while(spew != '\n')                 /* stdin吐出し                            */
            {                                   /*                                        */
                spew = fgetc(stdin);            /*                                        */
            }                                   /*                                        */
            spew = '\0';                        /*                                        */
        }                                       /*                                        */
                                                /*                                        */
        if((ans[0] == 'n' || ans[0] == 'N') && (ans[1] == '\n')) /* 継続判定              */
        {                                       /* 継続判定はnかN1文字                   */
            printf("正常終了\n");               /* 画面表示                               */
            break;                              /* 処理終了                               */
        }                                       /*                                        */
    }                                           /*                                        */
                                                /*                                        */
    return (rtnCode);                           /*                                        */
}

修正履歴

Borlandには"unistd.h", "getopt.h"が存在しないため、Maximaの中から強引に入手した。(実は必要なし?)
取得したファイルサイズを引数としてfread,fwriteを呼出し、一発コピーに成功した。

課題

  1. バイナリでなくテキストモードで同じことをすると、ファイル末尾に"\Comm"なるものが挿入される。
  2. コンパイル時にfopen_sを使うように警告が出る。
  3. mallocの仕様をよく理解していないので、free()するベストのタイミングがわからない。

    暇があればこれらについても調べてみます。

    1.について、Unix環境ではバイナリでの処理が基本のため、モードの違いによって動きが変わることはないみたい。
    2.コンパイラによって出たり出なかったり。
    3.誰か教えて。

  • 備考
    ファイルロックは自分で実装してください。

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2010-02-08 (月) 02:08:12 (5184d)