最速怪談選手権

読み込んだファイルがテキストファイルかバイナリファイルかを
プログラム上でわかる方法はありますでしょうか?

A 回答 (12件中1~10件)

> int Convert(const char* pInFileName, const char* pOutFileName)



関数のプロトタイプがそう指定されているのなら、入力ファイル・出力ファイルとも関数の外ではなく中でのfopen()を期待されていると思います。

> こちらのサイトのをまんまコピーし、変数名だけ変えてます。

これは、Convert()の中身がこのままということなのか、fgets()とfread()を入れ替えただけということなのか、どちらでしょう?
ということで、fread()を使ったConvert()のコード全体を補足に記述してください。
#状況説明を横着しちゃいけません

なお「課題」なら、なおさら中身を理解しなきゃ駄目です。

この回答への補足

#include<stdio.h>
#include<string.h>
#define MAX 10000 // 暫定的に最大値を決めてます

int Convert(const char* pInFileName, const char* pOutFileName);
int ReConvert(const char* pInFileName, const char* pOutFileName);

int main(){
int a,ret=-1;
char InFileName[MAX];// 入力ファイル名
char OutFileName[MAX];// 出力ファイル名
FILE *pInFileName;// 入力ファイルポインタ
FILE *pOutFileName;// 出力ファイルポインタ

printf("1:コンバート 2:リコンバート\n");
scanf("%d",&a);

/***** 入力ファイル名入力 *****/
printf("\n@@@@@入力ファイル名入力\n");
scanf("%s",&InFileName);
// 入力ファイルオープン
if((pInFileName=fopen(InFileName,"rb"))==NULL){
fclose(pInFileName);
printf("ファイルがありません\n");
return -1;
}

/***** 出力ファイル名入力 *****/
printf("\n@@@@@暗号化後ファイル名入力\n");
scanf("%s",&OutFileName);
// 出力ファイルオープン
if((pOutFileName=fopen(OutFileName,"rb"))!=NULL){
// read出来るのなら既にファイルあるという事なのでエラーにする
fclose(pOutFileName);
fclose(pInFileName);
printf("同名のファイルが既にあります\n");
return -1;
}
pOutFileName=fopen(OutFileName,"wb");

// 1:コンバート
// 2:リコンバート
// 1,2以外:終了
if(a==1){
ret=Convert((const char*)pInFileName,(const char*)pOutFileName);
}
else if(a==2){
ret=ReConvert((const char*)pInFileName,(const char*)pOutFileName);
}
if(ret==0){
printf("正常終了\n");
}
else{
printf("異常終了\n");
fclose(pOutFileName);
fclose(pInFileName);
return -1;
}
fclose(pOutFileName);
fclose(pInFileName);

printf("数字+エンターで終了します\n");
scanf("%d",&a);

return 0;
}

/*****コンバート*****/
int Convert(const char* pInFileName, const char* pOutFileName)
{
char moji[MAX];
int len;
int i;

len = fread( moji, 1, 10000, (FILE*)pInFileName );

for(i=0;i<len;i++) fprintf((FILE*)pOutFileName,"%02x",(unsigned char)moji[i]);
fprintf((FILE*)pOutFileName,"\n");

return 0;
}

/*****リコンバート*****/
int ReConvert(const char* pInFileName, const char* pOutFileName)
{
char moji16[MAX*2];// 16進表記
char moji10[MAX];// 文字配列
int i,j;
int len=MAX*2;
char *fg;// fgets用戻り値
memset(moji16,'\0',len);
memset(moji10,'\0',MAX);

//len = fread( moji16, 1, 10000, (FILE*)pInFileName );
fg=fgets(moji16,MAX*2,(FILE*)pInFileName);
if(fg==NULL) return -1;
len=strlen(moji16);

for(i=0,j=0;i<len;i+=2,j++){
sscanf(&moji16[i], "%2x", &moji10[j]);
putchar(*moji10);
}
for(j=0;j<len/2;j++) fprintf((FILE*)pOutFileName,"%c",moji10[j]);

return 0;
}

補足日時:2008/10/22 17:57
    • good
    • 0
この回答へのお礼

動きを見つつ、どこをどう変えたら、動きがどう変わるのかで
勉強するしかないかなと思ってます。

現在こんな感じですが、
テキスト→16進(BZで一致確認)→テキスト
画像→16進(BZで一致確認)
の確認は取れたのですが、
16進→画像はどこかおかしいようです。画像表示がされていないので・・
自分なりにも考えてみます。。

お礼日時:2008/10/22 18:01

これで読めないのは変だなぁ……とは思うのですが、それとは別にロジックのおかしい部分があります。



> len = fread( moji, 1, 10000, (FILE*)pInFileName );
> for(i=0;i<len;i++) fprintf((FILE*)pOutFileName,"%02x",(unsigned char)moji[i]);

fread()が必ず1回で終わってしまうので、最大で10000byteしか読めず大きなファイルには対応できません。len(fread()の返り値)が0になるまではループする必要があります。
##9のやり方が一番楽だとは思うけどコードに一部誤り(※)が。

> fprintf((FILE*)pOutFileName,"\n");

別に改行を入れる必要はないのでは。
#まぁ入れてもいいんですがいちいち除去する必要が。

※>#9
fread()の第一引数がポインタになってないですよ……

この回答への補足

おかげさまでできました。
ありがとうございます。

MAXが小さすぎましたのでint→longにしてMAXの値も
かなり大きくしてなんとか動くようにはなりました。

これを予め用意するのではなく、変換したいファイルに応じて
例えばもっと大きいファイルを用いたい場合にはどういった
方法を用いたら良いのでしょうか?

ちょっと見ていたところcallocで配列の要素を用意すると
あったのですが、その場合、どうやったらサイズを指定
出来るのでしょうか?バイナリですとstr系は使えない
とのことですし、freadでサイズは出るものの、第三引数に
何を入れたらよいのか困ってます。

補足日時:2008/10/23 14:06
    • good
    • 0

各関数がやる事はこれだけですね。


(1)ファイルを開く
(2)「データを読んで変換してファイルに書く」を繰り返す
(3)ファイルを閉じる
こんな感じ?
/* バイナリファイルを読んで、16進テキストでファイル出力 */
int Convert(const char *pInFileName, const char *pOutFileName) {
 FILE *InFp, *OutFp;
 int ch;
 InFp=fopen(pInFileName, "rb"); /* リード用ファイル */
 OutFp=fopen(pOutFileName, "w"); /* ライト用ファイル */
 while ((ch=fgetc(InFp))!=EOF) { /* 1バイトずつ読んで16進で書く */
  fprintf(OutFp,"%02x",ch&0xff);
 }
 fclose(InFp); /* ファイルを閉じる */
 fclose(OutFp);
 return 0;
}

/* 16進の1文字を数値に変換 */
int hex2dec(char c) {
 if (c>='0' && c<='9') return c-'0';
 if (c>='A' && c<='F') return c-'A'+10;
 if (c>='a' && c<='f') return c-'a'+10;
 return -1;
}

/* 16進テキストを読んで、バイナリでファイル出力 */
int ReConvert(const char *pInFileName, const char *pOutFileName) {
 FILE *InFp, *OutFp;
 int ch1, ch2;
 InFp=fopen(pInFileName, "r"); /* リード用ファイル */
 OutFp=fopen(pOutFileName, "wb"); /* ライト用ファイル */
 while ((ch1=fgetc(InFp))!=EOF) { /* 上位4ビットを読む */
  if ((ch2=fgetc(InFp))!=EOF) { /* 下位4ビットを読む */
   fputc(hex2dec(ch1)*16+hex2dec(ch2), OutFp);
  } else break;
 }
 fclose(InFp); /* ファイルを閉じる */
 fclose(OutFp);
 return 0;
}
(全角空白を使ってます)
    • good
    • 0

No.8


>16進→画像はどこかおかしいようです。画像表示がされていないので・・
>自分なりにも考えてみます。。
えーと、すでに何度も問題点は回答されてるのですが……

・fgets()は使わない(使えない)
 →読み込めたデータ長がわからないから。
・str***()系の関数は使用しない
 →str***()系の関数は「文字列操作」のための関数。
  C言語の「文字列」は連続したデータ列の先頭から「"NULL文字"=0x00」まで。
  いくら長いデータを読んでもstrlen()では先頭から0x00までの長さを返す。
  従って、0x00~0xffまでの任意のデータで構成されるバイナリデータの処理では使用できない。

この回答への補足

そうでした・・16進表記されたから、と思ってうっかりしてました。

補足日時:2008/10/23 09:20
    • good
    • 0

この関数の引数なら普通は


/*****コンバート*****/
int Convert(const char* pInFileName, const char* pOutFileName)
{
FILE *InFp, *OutFp;
unsigned char moji;

InFp = fopen(pInFileName,"rb");
OutFp = fopen(pOutFileName,"w")
while (fread( moji, 1, 1, InFp ))
{
fprintf(OutFp,"%02x", moji);
}
fclose(InFp);
fclose(OutFp);
return 0;
}
じゃないでしょうか
リコンバートはfgetsじゃ無理です
    • good
    • 0

No.5


>int Convert(const char* pInFileName, const char* pOutFileName)を使うこと。
>XXXX.txtもYYYY.bmpも読み込める事が条件になっているんです。
>ここは覆せないのでConvert関数の引数は変えられないですし、
これは了解しました。
しかしですね、それであれば普通は「ファイルポインタ」ではなく「ファイル名をそのまま」渡す記述の仕方ですよ。

>また、当初考えていたのでは、
(中略)
>となると、freadならばどちらも対応できるのでしょうか??
コンピューター概論のようなものは勉強しませんでしたか? No.1で
>テキストファイルも広義ではバイナリ(データの)ファイルですよ。
と書きましたよね。
プログラムであろうが、テキストファイルであろうが、画像データであろうがPC上では「バイナリデータ」でしかありません。
試しに、メモ帳にテキストデータ以外のファイルをドラッグしてみてください。
メモ帳は「開くものはすべてテキストデータだ」という処理しかありませんから、ドラッグしたデータをテキストデータとして扱った表示が行われます。


>>まさか・・
>それは、上記のとおりではないです。
いえ、前述の通りです。

>ヘッダ???のあたりは同じなんですが、そこから先は
>BZでは0000000000000・・・・、自作では00以外が乱立していて、
>どこからどこまでが省かれているかまでは把握できていません。
データが一致しないのはNo2や5のとおりです。
0x00をNULL文字として除外してしまい、
尚且つ「バイナリーデータ」を「文字データ」として出力しているのですから一致はしません。
    • good
    • 0

> 書いたコードは#2さんの補足に書いた通りです。



……あー、「fread()だとテキストが読めない」方のコードを提示してください。

> 0x00を省くのは何故なんでしょう?

うっかりしてましたが、正確には「各読み込みで最初の0x00以降を省いてしまう」ですね。
strlen()の戻り値は先頭から最初の'\0'(0x00)までの文字列長です。
したがって、件のコードでは読み込んだデータのうち0x00以降のデータが書き込まれない訳です。

この回答への補足

freadについては関数もあんまり理解できていないので、
こちらのサイトのをまんまコピーし、変数名だけ変えてます。
http://www.geocities.jp/ky_webid/c/037.html

補足日時:2008/10/22 16:39
    • good
    • 0
この回答へのお礼

非常にごちゃごちゃして長くなっておりますので
まとめさせていただきますと、最終的に望んでいるのは、

ファイル※を読み込み、別ファイルに16進表記で格納する
(※ XXXX.txtでもYYYY.bmpでも)
プログラムの作成。
条件として、
int Convert(const char* pInFileName, const char* pOutFileName)
を用いる事です。

お礼日時:2008/10/22 17:07

とりあえず、


str***()系の関数は「バイナリーデータ」には使用すべきではありません。
str***()系は「文字列」操作のための関数です。
C言語では文字列はNULL文字(通常は'\0'=0x00)までのデータを文字列として認識します。
strlen()は「文字列の長さ」を取得します。つまり、データの途中にNULL文字があればそこまでの長さしか取得しません。

それと、
>fprintf((FILE*)pOutFileName,"%02x",(unsigned char)moji[i]);
まさか↑の処理で出力されたファイルと、オリジナルのファイルをバイナリエディタで見て「違う」とか言ってませんよね?
例えば、
「01,02,00,03」のようなデータを提示の処理を通せば結果は、
「30,31,30,32,0d」ですよ。(わかりやすく"0x"と","を付加)
上記のとおりなら、printf()/fprintf()の出力書式「%…」を理解していないとどうしようもないですよ。

ああ、ここも微妙だ。
>int Convert(const char* pInFileName, const char* pOutFileName)
なぜ、FILE型をわざわざchar型にキャストしているのでしょうか?
(別に悪くはないけど、無駄だし"~Name"が誤解をまねく)

------
>結構いろんなところから参考になりそうなソース引っ張ってきて
>動かして動かなくての繰り返しですので・・
>本は一通りは読んだものの初心者用に書かれている内容として
>しかわかりませんし・・
プログラムは使用している処理や関数を理解していなければ作れるものではありません。
単に「持ってきて繋げてみた」というのが現状でしょう。
少なくとも、文字列の説明は初心者用の本にも乗っているはずの内容です。

この回答への補足

初心者用の本にも載ってるかもしれませんけど、
それは初級者以上の方の見方でそう捉える事が出来る、
のではないでしょうか・・・・?
本を読んでいると、結構「詳しい事はここでは省きます」的な
内容は多いですから。。
ちなみにバイナリの事は書いてありませんでした。

今回の課題には幾つか決まりがありまして、
int Convert(const char* pInFileName, const char* pOutFileName)を使うこと。
XXXX.txtもYYYY.bmpも読み込める事が条件になっているんです。
ここは覆せないのでConvert関数の引数は変えられないですし、
また、当初考えていたのでは、
XXXX.txtならばstrxxx関数
YYYY.bmpならばfreadとか
でやろうと思っていましたが、自動でどちらであるかの
認識はできないようですし、また、YYYY.bmpをstrxxx関数で読み込む
事もできないそうですね。となると、freadならばどちらも対応
できるのでしょうか??

>まさか・・
それは、上記のとおりではないです。
ヘッダ???のあたりは同じなんですが、そこから先は
BZでは0000000000000・・・・、自作では00以外が乱立していて、
どこからどこまでが省かれているかまでは把握できていません。

補足日時:2008/10/22 16:40
    • good
    • 0
この回答へのお礼

アドバイスを整理したところ、
テキスト/画像→16進は出来ました。
BZで一致確認。

引き続き、逆の16進→テキスト/画像も
作成中ですが、やはり同じようにやれば、
画像はグラフィックが表示されるのでしょうか?

ざっと簡単になりますが、作り込みと致しましては、
・コンバート
freadで読み込み、fprintfで書き込み
・リコンバート
fgetsで読み込み、fwriteで書き込み

お礼日時:2008/10/22 17:54

> len=strlen(moji);


> for(i=0;i<len;i++) fprintf((FILE*)pOutFileName,"%02x",(unsigned char)moji[i]);

このコードでは0x00を省いてしまいますから、出力結果とバイナリエディタで異なるのは当たり前です。

バイナリを扱う場合は読み込み・書き出しのサイズは自分で管理しましょう。

-- #3の続き
> そうですね、読み込めていないと言った方がよいでしょうか。
> 結果が空白になるので。

……いや、「詳しく」説明してくださいってば。
どんなコード書いたんですか?

この回答への補足

書いたコードは#2さんの補足に書いた通りです。

main関数では
if((pInFileName=fopen(InFileName,"rb"))==NULL){
fclose(pInFileName);
printf("ファイルがありません\n");
return -1;
}
ret=Convert((const char*)pInFileName,(const char*)pOutFileName);
等しか書いていませんし、16進で表記させるための処理はそれ(#2さんの補足)だけですね。
-----
0x00を省くのは何故なんでしょう?
あんまりC言語わかってないのもあると思います。
結構いろんなところから参考になりそうなソース引っ張ってきて
動かして動かなくての繰り返しですので・・
本は一通りは読んだものの初心者用に書かれている内容として
しかわかりませんし・・

補足日時:2008/10/22 16:09
    • good
    • 0

> freadを使うといった記載がありましたが、そうすると、「XXXX.txt」を読み込めず



「読み込めない」を詳しく補足してください。正しく使えば読めないはずがないので。

この回答への補足

そうですね、読み込めていないと言った方がよいでしょうか。
結果が空白になるので。

補足日時:2008/10/22 15:56
    • good
    • 0

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