プロが教える店舗&オフィスのセキュリティ対策術

現在、VC++6を用いて、MFC を使わずにアプリケーションを作っています。
アセンブラ経験はありますが、C言語経験がないので、四苦八苦しています。
今回、
csv形式のファイルを読込んで、配列に格納したいのですが上手くいきません。

c言語の場合は、fopen関数で開いたファイルを、fgets関数で1行づつ読込み、
strtok関数で、処理すれば良いということが分かりました。

ところが、VC++6のCreateFile関数では、ファイルのポインタの変わりに、
クラスのハンドルが返ってくるので、fgets関数は使えないような気がします。

なにかfgets関数の変わりになるような関数はあるのでしょうか。
質問の意味が分かりずらいかと思いますが、適当に汲み取って教えて下さい。
宜しくお願いします。

A 回答 (5件)

fgets に相当する WIN32API は存在しません。


CreateFile等 は fopen の上位バージョン?に該当する
とは言えない、別のものなので。

fgets,fopen 等・・・ファイルストリーム関数(ファイル入出力
の中でも、バッファリングによりデータ操作を向上させ
たもの)
CreateFile ・・・全般的な入出力に利用するAPI(ファイル
入出力も含め、デバイスI/O、共有メモリ、パイプ、
メールスロット等に利用)

ANSI-C のテキスト系操作関数はとっても便利なので、
WIN32API のみで処理しきるのは不可能です。
csv 操作などの部分は、 Win32アプリケーションでも
fopen-fgets-strtok で素直に作れば良いと思います。

但し、既述されてありますがMFCの CStdioFile は
本当に便利です。MFCを利用するかどうかは、どの
プラットホームかという根本的な話なので、このためだけ
にどうするかという話ではないとは思いますが。
個人的には CStdioFile::ReadLine の後 strtok の
分割 ってのが結構好みです。
    • good
    • 0
この回答へのお礼

アドバイスありがとうございます。
大変参考になりました。

>csv 操作などの部分は、 Win32アプリケーションでも
>fopen-fgets-strtok で素直に作れば良いと思います。

あ~ そうなんですか。え~
実はCreateFileとstrtokでソース書いちゃったんです。

(1) CreateFileでファイルを全部バッファに書き出す。
(2) strtokで改行文字'\n'を見つけ、1行ずつ分割する。
(3) strtokでカンマ','を見つけ、構造体に格納する。

結局、CreateFileとstrtokをごっちゃで使ったんですけど、
やっぱ変ですかね? 書き直したほうがいいのかしら。

ソースはこんな感じ。
//----------------------------------------------------------------------------

#define HR_CIKUMAX 20 // 地区データ最大値

struct TEST{
char Record[5]; //レコード番号
char BlockNo[5]; //地区番号
char BlockName[25]; //地区名
char Remark[35]; //備考
};

struct TEST test[HR_CIKUMAX];

DWORD dwRead;
char rdata[sizeof(test) +1];
char line[400];
char *token;
char *pdest;
int i,j;
int szline;
int offset;

// ファイルポインタがファイルの先頭に置かれるようにする
SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
ReadFile( hFile, rdata , sizeof(test), &dwRead, NULL ); // ファイルを全部読込む
rdata[dwRead] = 0x00;
// ファイルをクローズする
CloseHandle( hFile );

//変数初期化
i = j = 0;
offset = 0;
pdest = strchr( rdata , '\n' ); //改行文字検索(変数初期化)

while (pdest != NULL)
{
pdest = strchr( rdata +offset, '\n' ); //改行文字検索
szline = pdest - rdata +1 ; //改行までの文字数
strncpy( line, rdata +offset , szline );//1行分を書き出す
offset += szline; //ポインタを進める

token = strtok( line,"," ); //各行につき、最初のトークン取得
strcpy (test[i].Record, token);
token = strtok( NULL,"," );
strcpy (test[i].BlockNo, token);
token = strtok( NULL,"," );
strcpy (test[i].BlockName, token);
token = strtok( NULL,"," );
strcpy (test[i].Remark, token);
i++;
}

//----------------------------------------------------------------------------

お礼日時:2002/07/12 10:29

>実はCreateFileとstrtokでソース書いちゃったんです。


全取得でのバッファサイズ的に平気なら、別に良いんじゃ
ないでしょうか。・・・ただ、そーゆーのにうるさい人も
いるかも知れんです。

ループの頭 数行は
> while (pdest != NULL)
> {
> pdest = strchr( rdata +offset, '\n' ); //改行文字検索
> szline = pdest - rdata +1 ; //改行までの文字数
> strncpy( line, rdata +offset , szline );//1行分を書き出す
> offset += szline; //ポインタを進める
  ↓
while (1)
{
pdest = strchr( rdata +offset, '\n' ); //改行文字検索
if(pdest == NULL) // ※こっちで判定
break; // ※こっちで判定
szline = pdest - (rdata +offset) +1 ; //改行までの文字数 ※offset
strncpy( line, rdata +offset , szline );//1行分を書き出す
line[szline-1] = '\0'; // ※strncpy のNULL終端
offset += szline; //ポインタを進める

てな具合だと思います(※・・・多分修正)


fgets だとやはりこれ
---------------------------------------
FILE* f;
char line[sizeof(struct TEST)+2]; //バッファ領域ゆとり for fgets
char *token;
int i;

f = fopen("StorageCard\\APL\\HTRSBLOCK.CSV", "r+");
//変数初期化
i =0;
while(fgets( line, sizeof(line), f ))
{
line[strlen(line)-1] = '\0';
token = strtok( line,"," ); //各行につき、最初のトークン取得
strcpy (test[i].Record, token);
token = strtok( NULL,"," );
strcpy (test[i].BlockNo, token);
token = strtok( NULL,"," );
strcpy (test[i].BlockName, token);
token = strtok( NULL,"," );
strcpy (test[i].Remark, token);
i++;
}
fclose(f);
return i;
}
---------------------------------------
    • good
    • 0
この回答へのお礼

参考ソースありがとうございます。

>ただ、そーゆーのにうるさい人も
>いるかも知れんです。
僕も気にはなっていたのですが...

fopen-fgets-strtok だと大変分かりやすいですね。
とりあえず、ソースはパクらせて頂くことにしました。
まずは、fopenを使えるように勉強します。

CreateFileとCStringは、又の機会に使ってみます。
ありがとうございました。
ポイントは#No4_cheさんに発行します。
(結果は同じなんですけど、ぜひ#No4回答に発行したいので)

お礼日時:2002/07/15 17:17

MFCを使うと楽になりますよー。


構造体を使い始めているのならそれほど難しくは無いはずです。
今回のプログラムはCStringとCStdioFileを使えば簡単にできますよ。
CStringを使えば文字列をBASICのように使えますし、
CStdioFileを使えばテキストファイルを1行読み出すなんてことは朝飯前です。
ものすごく簡単に書きますと、

CString str;
CStdioFile f("FILE.CSV",CFile::modeRead|CFile::modeText);

while(f.ReadString(str))
{
// 1行の処理をする
str.TrimLeft(); // 行頭のスペース削除
strRec=str.Left(Find(',')); // トークン取得
str=str.Mid(Find(',')+1); // 次のトークン取得のため文字列をシフト

}

というような具合です。
    • good
    • 0
この回答へのお礼

MFC 魅力的ですね

>CStringを使えば文字列をBASICのように使えますし、
実はBASICも触ったことがないので、良く分からないのですが、(^_^;)

>CStdioFileを使えばテキストファイルを1行読み出すなんてことは朝飯前です。
これには魅力を感じています。

今回作成中のソフトはwindowsCE用で、練習教材みたいなものです。
MFCの練習にはちょうど良いかとも思いますが、今はちょっと。
なにせ、納期が押してるもので (^_^;)

次回、バージョンアップ時には是非MFCで作成してみます。

お礼日時:2002/07/12 10:07

入出力関数については体系の違うものを混ぜて使うのは良くないでしょう。

Cで使われる標準IOではfopenを使いますが、C++ではストリームIOの関数が使えます。またCreateFileというのはWin32APIの関数です。

VCはどの体系の関数を使ってもコンパイルできますが、一つのソースに混ぜるのは良くありません。

Win32APIまで使うのでしたらMFCを避ける理由はあまりないと思いますが?
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

>入出力関数については体系の違うものを混ぜて使うのは良くないでしょう。
ですよね。 なんとなく体系が違うような気はしていたのですが。

>C++ではストリームIOの関数が使えます。
ストリームIOの関数の意味について調べてみます。

>Win32APIまで使うのでしたらMFCを避ける理由はあまりないと思いますが?
C++の勉強の仕方を色々みてみると、最初はMFCを使わないほうがよさそうなことが書いてあったし、
cもc++も良く分かっていない自分には、MFCは敷居が高そうで...

お礼日時:2002/07/11 09:58

VC++だからといってC言語の関数が使えないということはありません。


fopenもfgetsも使えますよ。

C++はC言語の拡張されたものであり、
VC++はC++をウィンドウズのウィンドウ操作などを
楽にできるようにしたものです。

CreateFileでファイルのアクセスをするのは、
ReadFileとWriteFileでできます。
MSDNライブラリでCreateFileの解説の下のほうに関係ある関数が羅列されていますよ。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

ファイルのオープンは、いまさらfopenよりも、新しいCreateFile関数を使いたいと思っています。
ただ、fgetsや、strtokも便利そうなので使ったほうが良いかと思っていました。。

ReadFileをつかうと、1文字づつ評価して、自分でレコードやトークンを見つけて、
配列(実は構造体)に格納しなければいけないんですよね。
結構難しそうなので、fgetsや、strtokの代わりの関数があれば楽かと...。

具体的には20行4列のデータをファイルから読込み、構造体に格納して処理したいのです。

コードは下記のような感じになると思いますが、構造体、及びポインタの使い方が
いまだ良く分かっていないため、このままでは動かないと思います。
なにせ、CreateFile関数とfgets関数をごっちゃに使おうとしているくらいですから (..;)


//***************************************************************
//***************************************************************
#define HR_CIKUMAX20// 地区データ最大値

struct TEST{
char Record[5];//レコード番号
char BlockNo[5];//地区番号
char BlockName[25];//地区名
char Remark[35];//備考
};

struct TEST test[HR_CIKUMAX];

char line[400], result;
int i,j;
// ファイルをオープンする
hFile = CreateFile(
TEXT("\\StorageCard\\APL\\HTRSBLOCK.CSV") ,// ファイル名
GENERIC_READ | GENERIC_WRITE,// アクセスモード
0,// 共有モード
NULL,// セキュリティ記述子
OPEN_EXISTING,// 作成方法
FILE_ATTRIBUTE_NORMAL,// ファイル属性
NULL// テンプレートファイルのハンドル
);
// ファイルポインタがファイルの先頭に置かれるようにする
SetFilePointer( hFile, 0, NULL, FILE_BEGIN );

//変数初期化
i = j = 0;
result = 0;

while( fgets( line, 400, ???? ) != NULL)
//ファイルエンドまで行単位で読込みたいが、ファイルポインタをどうすればいいのか分かりません。
{
test[i].Record[0] = *strtok( line,"," );//各行につき、最初のトークン取得
while(result != NULL)
result=(test[i].Record[j++] = *strtok( NULL,"," ));
i++;
}

//**********************************************************
//**********************************************************

お礼日時:2002/07/11 09:49

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!