• ベストアンサー

読み込んだファイル

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

質問者が選んだベストアンサー

  • ベストアンサー
  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.8

> int Convert(const char* pInFileName, const char* pOutFileName) 関数のプロトタイプがそう指定されているのなら、入力ファイル・出力ファイルとも関数の外ではなく中でのfopen()を期待されていると思います。 > こちらのサイトのをまんまコピーし、変数名だけ変えてます。 これは、Convert()の中身がこのままということなのか、fgets()とfread()を入れ替えただけということなのか、どちらでしょう? ということで、fread()を使ったConvert()のコード全体を補足に記述してください。 #状況説明を横着しちゃいけません なお「課題」なら、なおさら中身を理解しなきゃ駄目です。

sakuranb22
質問者

お礼

動きを見つつ、どこをどう変えたら、動きがどう変わるのかで 勉強するしかないかなと思ってます。 現在こんな感じですが、 テキスト→16進(BZで一致確認)→テキスト 画像→16進(BZで一致確認) の確認は取れたのですが、 16進→画像はどこかおかしいようです。画像表示がされていないので・・ 自分なりにも考えてみます。。

sakuranb22
質問者

補足

#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; }

その他の回答 (11)

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.12

これで読めないのは変だなぁ……とは思うのですが、それとは別にロジックのおかしい部分があります。 > 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()の第一引数がポインタになってないですよ……

sakuranb22
質問者

補足

おかげさまでできました。 ありがとうございます。 MAXが小さすぎましたのでint→longにしてMAXの値も かなり大きくしてなんとか動くようにはなりました。 これを予め用意するのではなく、変換したいファイルに応じて 例えばもっと大きいファイルを用いたい場合にはどういった 方法を用いたら良いのでしょうか? ちょっと見ていたところcallocで配列の要素を用意すると あったのですが、その場合、どうやったらサイズを指定 出来るのでしょうか?バイナリですとstr系は使えない とのことですし、freadでサイズは出るものの、第三引数に 何を入れたらよいのか困ってます。

回答No.11

各関数がやる事はこれだけですね。 (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; } (全角空白を使ってます)

  • arain
  • ベストアンサー率27% (292/1049)
回答No.10

No.8 >16進→画像はどこかおかしいようです。画像表示がされていないので・・ >自分なりにも考えてみます。。 えーと、すでに何度も問題点は回答されてるのですが…… ・fgets()は使わない(使えない)  →読み込めたデータ長がわからないから。 ・str***()系の関数は使用しない  →str***()系の関数は「文字列操作」のための関数。   C言語の「文字列」は連続したデータ列の先頭から「"NULL文字"=0x00」まで。   いくら長いデータを読んでもstrlen()では先頭から0x00までの長さを返す。   従って、0x00~0xffまでの任意のデータで構成されるバイナリデータの処理では使用できない。

sakuranb22
質問者

補足

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

  • php504
  • ベストアンサー率42% (926/2160)
回答No.9

この関数の引数なら普通は /*****コンバート*****/ 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じゃ無理です

  • arain
  • ベストアンサー率27% (292/1049)
回答No.7

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文字として除外してしまい、 尚且つ「バイナリーデータ」を「文字データ」として出力しているのですから一致はしません。

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.6

> 書いたコードは#2さんの補足に書いた通りです。 ……あー、「fread()だとテキストが読めない」方のコードを提示してください。 > 0x00を省くのは何故なんでしょう? うっかりしてましたが、正確には「各読み込みで最初の0x00以降を省いてしまう」ですね。 strlen()の戻り値は先頭から最初の'\0'(0x00)までの文字列長です。 したがって、件のコードでは読み込んだデータのうち0x00以降のデータが書き込まれない訳です。

sakuranb22
質問者

お礼

非常にごちゃごちゃして長くなっておりますので まとめさせていただきますと、最終的に望んでいるのは、 ファイル※を読み込み、別ファイルに16進表記で格納する (※ XXXX.txtでもYYYY.bmpでも) プログラムの作成。 条件として、 int Convert(const char* pInFileName, const char* pOutFileName) を用いる事です。

sakuranb22
質問者

補足

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

  • arain
  • ベストアンサー率27% (292/1049)
回答No.5

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

sakuranb22
質問者

お礼

アドバイスを整理したところ、 テキスト/画像→16進は出来ました。 BZで一致確認。 引き続き、逆の16進→テキスト/画像も 作成中ですが、やはり同じようにやれば、 画像はグラフィックが表示されるのでしょうか? ざっと簡単になりますが、作り込みと致しましては、 ・コンバート freadで読み込み、fprintfで書き込み ・リコンバート fgetsで読み込み、fwriteで書き込み

sakuranb22
質問者

補足

初心者用の本にも載ってるかもしれませんけど、 それは初級者以上の方の見方でそう捉える事が出来る、 のではないでしょうか・・・・? 本を読んでいると、結構「詳しい事はここでは省きます」的な 内容は多いですから。。 ちなみにバイナリの事は書いてありませんでした。 今回の課題には幾つか決まりがありまして、 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以外が乱立していて、 どこからどこまでが省かれているかまでは把握できていません。

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.4

> len=strlen(moji); > for(i=0;i<len;i++) fprintf((FILE*)pOutFileName,"%02x",(unsigned char)moji[i]); このコードでは0x00を省いてしまいますから、出力結果とバイナリエディタで異なるのは当たり前です。 バイナリを扱う場合は読み込み・書き出しのサイズは自分で管理しましょう。 -- #3の続き > そうですね、読み込めていないと言った方がよいでしょうか。 > 結果が空白になるので。 ……いや、「詳しく」説明してくださいってば。 どんなコード書いたんですか?

sakuranb22
質問者

補足

書いたコードは#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言語わかってないのもあると思います。 結構いろんなところから参考になりそうなソース引っ張ってきて 動かして動かなくての繰り返しですので・・ 本は一通りは読んだものの初心者用に書かれている内容として しかわかりませんし・・

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.3

> freadを使うといった記載がありましたが、そうすると、「XXXX.txt」を読み込めず 「読み込めない」を詳しく補足してください。正しく使えば読めないはずがないので。

sakuranb22
質問者

補足

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

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.2

すべての文字を検査するしかない。そして、検査しても「どうやら、テキストっぽい」とか「きっと、バイナリっぽい」くらいしか判らない。 C言語にとっては「読み込まれたファイル」が「テキストファイルなのか」「バイナリファイルなのか」は区別されない。 単に「バイナリモードで開けと言われたら、バイナリファイルとして扱う」か「テキストモードで開けと言われたら、テキストファイルとして扱う」だけの話。 例えば、あるプログラムで、4バイトのバイナリデータをファイルに書き込みする処理があったとしよう。 その4バイトが、順に、65、66、13、10、だったとしよう。 書き込みしたプログラムから見れば、このファイルは「バイナリファイル」になる。 しかし、出来上がったファイルを「メモ帖」で読み込むと、何故か AB<改行> と言う文字が出てきて、メモ帖でテキストファイルを開いたのと同じ結果になる。 つまり、同じファイルが、書き込みしたプログラムから見ればバイナリファイルだし、メモ帖から見ればテキストファイルになる、って事。 強いて言えば「ファイルの中身に、バイナリとかテキストとかの区別なんかない」って事。 「バイナリとかテキストとかの区別なんかない」んだから、何をどう調べてみた所で、判るのは「どうやら、テキストっぽい」とか「きっと、バイナリっぽい」くらい。 結論は「プログラム上で判る方法なんてない」「そもそも、ファイルにテキストとかバイナリとかの区別なんかない」って事。

sakuranb22
質問者

補足

ひとつのプログラムで「XXXX.txt」「YYYY.bmp」のどちらをも 16進表記で別ファイルに保存するプログラムを作っております。 調べておりますと、バイナリファイルを化けずに読み込むには freadを使うといった記載がありましたが、そうすると、 「XXXX.txt」を読み込めず、逆に下記プログラムを用いると 「XXXX.txt」は大丈夫であるが、「YYYY.bmp」の方は 「YYYY.bmp」そのものをBZにて変換かけた値と比べると異なっておりました。 どちらのファイルでも正しく16進表記は出来ないのでしょうか? それとも、単にBZにて変換かけたようには出来ないということですか? /*****コンバート*****/ int Convert(const char* pInFileName, const char* pOutFileName) { char moji[MAX]; int i; int len=MAX; char *fg; // fgets用戻り値 while(1){ fg=fgets(moji,MAX,(FILE*)pInFileName); if(fg==NULL) break; len=strlen(moji); for(i=0;i<len;i++) fprintf((FILE*)pOutFileName,"%02x",(unsigned char)moji[i]); fprintf((FILE*)pOutFileName,"\n"); } return 0; }

関連するQ&A