C 言語による C 言語ファイル操作
どうも,筆者です.
今回は,C 言語を用いて,C 言語ファイルの簡易的な編集を行う.プログラムの勉強であり,実用性は皆無である.
目的
ここでは,C 言語のソースコードを読み込んで,コメントとそれ以外のコードに分けるという操作を行う. ここで,
- ソースコード内のタブは読み飛ばす.
- スペースは保持する.
- コメントは,そのまま出力する.
- コメント以外のコードは,指定した文字列以内に収まるように,出力する.この時,改行コードは無視する.
という条件で処理を行う.すなわち,ある程度決まった長さで,コードを区切り,出力するプログラムとなる.
サンプル
今回は,楕円の中心,長軸の長さ,短軸の長さ,回転角の情報を読み取り,構造体に代入するというプログラムを例に,出力結果を示す.
void readPhantom(char *fileName, int numberOfPhantoms, PHANTOM *phantom, int *result){ FILE *fp; int iCnt; double paramReal[5]; if(*result < 0){ *result = -1; } else if(NULL == (fp = fopen(fileName, "r"))){ fprintf(stderr, "%s can't open\n", fileName); *result = -1; } else{ *result = 1; for(iCnt = 0; iCnt < numberOfPhantoms; iCnt++){ if( fscanf(fp, "%lf %lf %lf %lf %lf", ¶mReal[0], ¶mReal[1], ¶mReal[2], ¶mReal[3], ¶mReal[4]) != 5 ){ fprintf(stderr, "%s: format is illegal\n", fileName); *result = -1; iCnt = numberOfPhantoms; } else{ phantom[iCnt].x0 = paramReal[0]; phantom[iCnt].y0 = paramReal[1]; phantom[iCnt].A = paramReal[2]; phantom[iCnt].B = paramReal[3]; phantom[iCnt].alpha = paramReal[4]; } } fclose(fp); } }
これをプログラムに投げると,
void readPhantom(char *fileName, int numberOfPhantoms, PHANTOM *phantom, int *result){FILE *fp;int iCnt;double paramReal[5];if(*result < 0){*result = -1;}else if(NULL == (fp = fopen(fileName, "r"))){fprintf(stderr, "%s can't open\n", fileName);*result = -1;}else{*result = 1;for(iCnt = 0; iCnt < numberOfPhantoms; iCnt++){if(fscanf(fp, "%lf %lf %lf %lf %lf", ¶mReal[0], ¶mReal[1], ¶mReal[2], ¶mReal[3], ¶mReal[4]) != 5){fprintf(stderr, "%s: format is illegal\n", fileName);*result = -1;iCnt = numberOfPhantoms;}else{phantom[iCnt].x0 = paramReal[0];phantom[iCnt].y0 = paramReal[1];phantom[iCnt].A = paramReal[2];phantom[iCnt].B = paramReal[3];phantom[iCnt].alpha = paramReal[4];}}fclose(fp);}}
こうなる.もちろん,コンパイルもできる.
プログラム
たいした処理はしていないが,プログラムがあるので,載せておく.
#include<stdio.h> #include<stdlib.h> #define MAX_STRING_LENGTH (128) typedef unsigned char UI1; void printString(int iNum, char sz_buf[]); int main(void){ int iCnt, iDummy; char chReadChar, chComment; char sz_buf[MAX_STRING_LENGTH]; chReadChar = chComment = 0; iCnt = iDummy = 0; while(EOF != scanf("%c", &chReadChar)){ /* ヘッダーの出力 */ if('#' == chReadChar){ if(iCnt > 0){ sz_buf[iCnt] = '\0'; printString(iCnt, sz_buf); printf("\n"); iCnt = 0; } /* # から始まるものは,改行が出力するまで書き出す */ while('\n' != chReadChar){ printf("%c", chReadChar); iDummy = scanf("%c", &chReadChar); } printf("\n"); continue; } /* コメントの判定 */ if('/' == chReadChar){ iDummy = scanf("%c", &chReadChar); if(('*' != chReadChar) && ('/' != chReadChar)){ if(iCnt + 2 >= (int)MAX_STRING_LENGTH){ sz_buf[iCnt] = '\0'; printString(iCnt, sz_buf); iCnt = 0; } sz_buf[iCnt++] = '/'; sz_buf[iCnt++] = chReadChar; } else{ /* 複数行コメントの場合 */ sz_buf[iCnt] = '\0'; printString(iCnt, sz_buf); printf("\n"); iCnt = 0; if('*' == chReadChar){ printf("/"); printf("*"); chComment = 1; while(1 == chComment){ iDummy = scanf("%c", &chReadChar); if('\t' == chReadChar){ chReadChar = ' '; } printf("%c", chReadChar); if('*' == chReadChar){ iDummy = scanf("%c", &chReadChar); if('\t' == chReadChar){ chReadChar = ' '; } printf("%c", chReadChar); if('/' == chReadChar){ chComment = 0; printf("\n"); } } } } else{ /* 1 行コメントの場合 */ printf("//"); iDummy = scanf("%c", &chReadChar); while('\n' != chReadChar){ printf("%c", chReadChar); iDummy = scanf("%c", &chReadChar); } printf("\n"); } } } else if('"' == chReadChar){ sz_buf[iCnt] = '\0'; printString(iCnt, sz_buf); iCnt = 0; printf("%c", chReadChar); iDummy = scanf("%c", &chReadChar); while('"' != chReadChar){ printf("%c", chReadChar); iDummy = scanf("%c", &chReadChar); } printf("%c", chReadChar); } else{ /* 改行文字とタブは読み飛ばす */ if(('\n' == chReadChar) || ('\t' == chReadChar)){ continue; } /* NULL文字を挿入し,文字列を出力 */ if(iCnt + 2 >= (int)MAX_STRING_LENGTH){ sz_buf[iCnt] = '\0'; printString(iCnt, sz_buf); iCnt = 0; } /* 読み込んだ文字列を格納 */ sz_buf[iCnt++] = chReadChar; } } /* 残った文字列を出力 */ sz_buf[iCnt] = '\0'; printf("%s\n", sz_buf); iCnt = iDummy; return 0; } void printString(int iNum, char sz_buf[]){ int iCnt, iSpaceCnt, isSpacePoint; iSpaceCnt = 0; /* スペースの数を探索 */ for(iCnt = 0; iCnt < iNum - 1; iCnt++){ if(' ' == sz_buf[iCnt]){ iSpaceCnt++; isSpacePoint = iCnt; } } /* スペースが 1 つ以上ある場合 */ if(iSpaceCnt > 1){ /* 最後の文字だけ別に出力(途中で文字が切れるのを防ぐため) */ /* int iCnt, iSpaceCnt, isSpacePoint;for(iCnt = 0; iCnt < iNum - 1; iCnt++){if(' ' == sz_bu f[iCnt]){iSpaceCnt++;isSpacePoint = iCnt;}} とならないようにするため(sz_bu という変数として認識される) */ sz_buf[isSpacePoint] = '\0'; printf("%s\n", sz_buf); printf("%s", &sz_buf[isSpacePoint + 1]); } /* スペースが 1 つの場合 */ else{ /* そのまま出力 */ printf("%s", sz_buf); } return; }
実験
ここでは,前回作成した CSV ファイルを読み出すプログラムを入力し,出力を確認する.まず,ものとプログラムは,以下のようになっている.前回のものをくっつけただけである.
#include<stdio.h> #include<stdlib.h> typedef enum { RETURN_OK = 0, ARGUMENT_ERROR, FILE_OPEN_ERROR, MALLOC_ERROR } RETURN_TYPE; /* iCountRowCol: 行数と列数をカウントする char *pszFileName: 読み込むファイル名 unsigned int *piRow: 行数 unsigned int *piCol: 列数 return: 正常終了 -> 0 異常終了 -> 0 以外 */ int iCountRowCol(char *pszFileName, unsigned int *puiRow, unsigned int *puiCol){ FILE *prFile; int iRet; unsigned int uiRow, uiCol; char chData; iRet = RETURN_OK; /* 引数のチェック */ if((NULL == pszFileName) || (NULL == puiRow) || (NULL == puiCol)){ fprintf(stderr, "argument error\n"); iRet = ARGUMENT_ERROR; goto EXIT_COUNT_ROWCOL; } else{ *puiRow = *puiCol = 0; } if(NULL == (prFile = fopen(pszFileName, "r"))){ fprintf(stderr, "Error: %s cannot open\n", pszFileName); iRet = FILE_OPEN_ERROR; goto EXIT_COUNT_ROWCOL; } uiRow = uiCol = 0; while(EOF != fscanf(prFile, "%c", &chData)){ /* カンマの場合 */ if(',' == chData){ uiCol++; } /* 改行コードの場合 */ if('\n' == chData){ uiCol++; uiRow++; } } uiCol /= uiRow; *puiRow = uiRow; *puiCol = uiCol; fclose(prFile); EXIT_COUNT_ROWCOL: return iRet; } /* iMallocInt: int 型の malloc を行う unsigned int uiSize: 確保するサイズ int **ppiArray: 確保先のアドレス return: 正常終了 -> 0 異常終了 -> 0 以外 */ int iMallocInt(unsigned int uiSize, int **ppiArray){ unsigned int uiCnt; int iRet; iRet = RETURN_OK; /* 引数チェック */ if(NULL == ppiArray){ iRet = ARGUMENT_ERROR; goto EXIT_MALLOC_INT; } /* malloc */ if(NULL == (*ppiArray = (int *)malloc(sizeof(int) * uiSize))){ fprintf(stderr, "malloc error\n"); iRet = MALLOC_ERROR; goto EXIT_MALLOC_INT; } else{ for(uiCnt = 0; uiCnt < uiSize; uiCnt++){ (*ppiArray)[uiCnt] = 0; } } EXIT_MALLOC_INT: return iRet; } /* freeData: 確保した領域を開放する void *pvData: 確保した領域の先頭アドレス */ void freeData(void *pvData){ if(NULL != pvData){ free(pvData); } return; } /* iReadData: データの読み込み char *pszFileName: 読み込むファイル名 unsigned int uiRow: ファイルの行数 unsigned int uiCol: ファイルの列数 int *piArray: データの格納先 return: 正常終了 -> 0 異常終了 -> 0 以外 */ int iReadData(char *pszFileName, unsigned int uiRow, unsigned int uiCol, int *piArray){ FILE *prFile; char chData; int iRet; unsigned int uiCntRow, uiCntCol, uiCharCnt; char achInputDataList[11]; iRet = RETURN_OK; /* 引数のチェック */ if(NULL == pszFileName){ iRet = ARGUMENT_ERROR; goto EXIT_READ_DATA; } /* ファイルオープン */ if(NULL == (prFile = fopen(pszFileName, "r"))){ fprintf(stderr, "Error: %s cannot open\n", pszFileName); iRet = FILE_OPEN_ERROR; goto EXIT_READ_DATA; } /* ファイルの読み込み */ for(uiCntRow = 0; uiCntRow < uiRow; uiCntRow++){ for(uiCntCol = 0; uiCntCol < uiCol; uiCntCol++){ uiCharCnt = 0; achInputDataList[0] = '\0'; /* 1 文字ずつ読み込む */ while(EOF != fscanf(prFile, "%c", &chData)){ /* 「,」または「\n」が来た場合,ループを抜ける */ if((',' == chData) || ('\n' == chData)){ break; } /* 今回は,数値の部分だけ保存 */ if(((int)'0' <= (int)chData) && ((int)chData <= (int)'9')){ achInputDataList[uiCharCnt++] = chData; } } achInputDataList[uiCharCnt] = '\0'; piArray[uiCntRow * uiCol + uiCntCol] = atoi(achInputDataList); } } fclose(prFile); EXIT_READ_DATA: return iRet; } /* iReadCSVFile: CSV ファイルからデータを読み込む char *pszFileName: 読み込むファイル名 unsigned int *piRow: 行数 unsigned int *piCol: 列数 int **ppiArray: 確保先のアドレス return: 正常終了 -> 0 異常終了 -> 0 以外 */ int iReadCSVFile(char *pszFileName, unsigned int *puiRow, unsigned int *puiCol, int **ppiArray){ int iRet; unsigned int uiSize = 0; iRet = iCountRowCol(pszFileName, puiRow, puiCol); if(RETURN_OK != iRet){ fprintf(stderr, "Error: iCountRowCol\n"); goto EXIT_READ_CSV_FILE; } uiSize = (*puiRow) * (*puiCol); iRet = iMallocInt(uiSize, ppiArray); if(RETURN_OK != iRet){ fprintf(stderr, "Error: iMallocInt\n"); goto EXIT_READ_CSV_FILE; } iRet = iReadData(pszFileName, *puiRow, *puiCol, *ppiArray); if(RETURN_OK != iRet){ fprintf(stderr, "Error: iReadData\n"); goto EXIT_READ_CSV_FILE; } EXIT_READ_CSV_FILE: return iRet; } void printData(unsigned int uiRow, unsigned int uiCol, int *piArray){ unsigned int uiCntRow, uiCntCol; for(uiCntRow = 0; uiCntRow < uiRow; uiCntRow++){ for(uiCntCol = 0; uiCntCol < uiCol; uiCntCol++){ printf("%d ", piArray[uiCntRow * uiCol + uiCntCol]); } printf("\n"); } } int main(int iArgCnt, char **ppchArgVec){ int iRet; unsigned int uiRow, uiCol; int *piArray; if(iArgCnt == 2){ iRet = iReadCSVFile(ppchArgVec[1], &uiRow, &uiCol, &piArray); if(iRet == RETURN_OK){ printData(uiRow, uiCol, piArray); freeData((void *)piArray); } } return 0; }
次に,プログラムにより出力したコードを示す.
#include<stdio.h> #include<stdlib.h> typedef enum {RETURN_OK = 0,ARGUMENT_ERROR,FILE_OPEN_ERROR,MALLOC_ERROR} RETURN_TYPE; /* iCountRowCol: 行数と列数をカウントする char *pszFileName: 読み込むファイル名 unsigned int *piRow: 行数 unsigned int *piCol: 列数 return: 正常終了 -> 0 異常終了 -> 0 以外 */ int iCountRowCol(char *pszFileName, unsigned int *puiRow, unsigned int *puiCol){FILE *prFile;int iRet;unsigned int uiRow, uiCol;char chData;iRet = RETURN_OK; /* 引数のチェック */ if((NULL == pszFileName) || (NULL == puiRow) || (NULL == puiCol)){fprintf(stderr, "argument error\n");iRet = ARGUMENT_ERROR;goto EXIT_COUNT_ROWCOL;}else{*puiRow = *puiCol = 0;}if(NULL == (prFile = fopen(pszFileName, "r"))){fprintf(stderr, "Error: %s cannot open\n", pszFileName);iRet = FILE_OPEN_ERROR;goto EXIT_COUNT_ROWCOL;}uiRow = uiCol = 0;while(EOF != fscanf(prFile, "%c", &chData)){ /* カンマの場合 */ if(',' == chData){uiCol++;} /* 改行コードの場合 */ if('\n' == chData){uiCol++;uiRow++;}}uiCol /= uiRow;*puiRow = uiRow;*puiCol = uiCol;fclose(prFile);EXIT_COUNT_ROWCOL:return iRet;} /* iMallocInt: int 型の malloc を行う unsigned int uiSize: 確保するサイズ int **ppiArray: 確保先のアドレス return: 正常終了 -> 0 異常終了 -> 0 以外 */ int iMallocInt(unsigned int uiSize, int **ppiArray){unsigned int uiCnt;int iRet;iRet = RETURN_OK; /* 引数チェック */ if(NULL == ppiArray){iRet = ARGUMENT_ERROR;goto EXIT_MALLOC_INT;} /* malloc */ if(NULL == (*ppiArray = (int *)malloc(sizeof(int) * uiSize))){fprintf(stderr, "malloc error\n");iRet = MALLOC_ERROR;goto EXIT_MALLOC_INT;}else{for(uiCnt = 0; uiCnt < uiSize; uiCnt++){(*ppiArray)[uiCnt] = 0;}}EXIT_MALLOC_INT:return iRet;} /* freeData: 確保した領域を開放する void *pvData: 確保した領域の先頭アドレス */ void freeData(void *pvData){if(NULL != pvData){free(pvData);}return;} /* iReadData: データの読み込み char *pszFileName: 読み込むファイル名 unsigned int uiRow: ファイルの行数 unsigned int uiCol: ファイルの列数 int *piArray: データの格納先 return: 正常終了 -> 0 異常終了 -> 0 以外 */ int iReadData(char *pszFileName, unsigned int uiRow, unsigned int uiCol, int *piArray){FILE *prFile;char chData;int iRet;unsigned int uiCntRow, uiCntCol, uiCharCnt;char achInputDataList[11];iRet = RETURN_OK; /* 引数のチェック */ if(NULL == pszFileName){iRet = ARGUMENT_ERROR;goto EXIT_READ_DATA;} /* ファイルオープン */ if(NULL == (prFile = fopen(pszFileName, "r"))){fprintf(stderr, "Error: %s cannot open\n", pszFileName);iRet = FILE_OPEN_ERROR;goto EXIT_READ_DATA;} /* ファイルの読み込み */ for(uiCntRow = 0; uiCntRow < uiRow; uiCntRow++){for(uiCntCol = 0; uiCntCol < uiCol; uiCntCol++){uiCharCnt = 0;achInputDataList[0] = '\0'; /* 1 文字ずつ読み込む */ while(EOF != fscanf(prFile, "%c", &chData)){ /* 「,」または「\n」が来た場合,ループを抜ける */ if((',' == chData) || ('\n' == chData)){break;} /* 今回は,数値の部分だけ保存 */ if(((int)'0' <= (int)chData) && ((int)chData <= (int)'9')){achInputDataList[uiCharCnt++] = chData;}}achInputDataList[uiCharCnt] = '\0';piArray[uiCntRow * uiCol + uiCntCol] = atoi(achInputDataList);}}fclose(prFile);EXIT_READ_DATA:return iRet;} /* iReadCSVFile: CSV ファイルからデータを読み込む char *pszFileName: 読み込むファイル名 unsigned int *piRow: 行数 unsigned int *piCol: 列数 int **ppiArray: 確保先のアドレス return: 正常終了 -> 0 異常終了 -> 0 以外 */ int iReadCSVFile(char *pszFileName, unsigned int *puiRow, unsigned int *puiCol, int **ppiArray){int iRet;unsigned int uiSize = 0;iRet = iCountRowCol(pszFileName, puiRow, puiCol);if(RETURN_OK != iRet){fprintf(stderr, "Error: iCountRowCol\n");goto EXIT_READ_CSV_FILE;}uiSize = (*puiRow) * (*puiCol);iRet = iMallocInt(uiSize, ppiArray);if(RETURN_OK != iRet){fprintf(stderr, "Error: iMallocInt\n");goto EXIT_READ_CSV_FILE;}iRet = iReadData(pszFileName, *puiRow, *puiCol, *ppiArray);if(RETURN_OK != iRet){fprintf(stderr, "Error: iReadData\n");goto EXIT_READ_CSV_FILE;}EXIT_READ_CSV_FILE:return iRet;}void printData(unsigned int uiRow, unsigned int uiCol, int *piArray){unsigned int uiCntRow, uiCntCol;for(uiCntRow = 0; uiCntRow < uiRow; uiCntRow++){for(uiCntCol = 0; uiCntCol < uiCol; uiCntCol++){printf("%d ", piArray[uiCntRow * uiCol + uiCntCol]);}printf("\n");}}int main(int iArgCnt, char **ppchArgVec){int iRet;unsigned int uiRow, uiCol;int *piArray;if(iArgCnt == 2){iRet = iReadCSVFile(ppchArgVec[1], &uiRow, &uiCol, &piArray);if(iRet == RETURN_OK){printData(uiRow, uiCol, piArray);freeData((void *)piArray);}}return 0;}
少し読みにくいが,これでもちゃんとコンパイルがとおり,実行結果も一致する.次回何か書くことがあったら,もっと実用的なものを作成したい.