''[[FrontPage]]''
* ファイルの入出力2 [#ya50b151]
UNIX上でテキストファイルのコピーを行う実験プログラム。

** 制約 [#g3826ebb]
コピーするのに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);                           /*                                        */
 }
*** 修正履歴 [#tad8719c]
Borlandには"unistd.h", "getopt.h"が存在しないため、Maximaの中から強引に入手した。(実は必要なし?)~
取得したファイルサイズを引数としてfread,fwriteを呼出し、一発コピーに成功した。~
~
*** 課題 [#v760a770]
+バイナリでなくテキストモードで同じことをすると、ファイル末尾に"\Comm"なるものが挿入される。
+コンパイル時にfopen_sを使うように警告が出る。
+mallocの仕様をよく理解していないので、free()するベストのタイミングがわからない。~
~
暇があればこれらについても調べてみます。~
~
1.について、Unix環境ではバイナリでの処理が基本のため、モードの違いによって動きが変わることはないみたい。~
2.コンパイラによって出たり出なかったり。~
3.誰か教えて。~
~
-備考~
ファイルロックは自分で実装してください。

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS