チョコミントアイス

あるプログラムでバイナリ出力しているファイルがあります。これを単純にfread()で読み込んで、今度はfprintf()で出力すればどうなりますか?やりたいことは、バイナリ出力されたファイルをテキストファイルに変換したいのですが、この方法で、バイナリファイルが読めるでしょうか?
ちなみに、読みたいバイナリファイルは、fwrite()で書き出したファイルです。
あと、「バイナリファイルです」と言って貰ったファイルを、windowsのテキストエディタなどで開くと、appleなどの通常のアルファベットの単語と、あとは訳のわからないものが見えるのですが、これってバイナリファイルじゃないですよね?appleなどと書いてあるのですから。
間違えていましたら、訂正お願いします。

A 回答 (7件)

状況は大体つかめました。

HP-UX→Linux(INTEL?)なので、ビック→リトルのエンディアン変換が必要だと思われます。
データフォーマットを見る限り、エンディアン変換は以下の部分で必要です。
>struct{
>int i_data; ← エンディアン変換が必要です。
>char s_data[32][16];
>float d_data[32]; ← エンディアン変換が必要です。
>}A;

>i_dataが一連のデータのインデックスになっていて、i_dataの分だけs_dataとd_dataが繰り返されます。

ここの詳細が不明なのですが、次の構造体のイメージでしょうか?
struct DATA {
char s_data[32][16];
float d_data[32]; ← エンディアン変換が必要です。
};
struct {
int i_data; ← エンディアン変換が必要です。
struct DATA datas[]; ← i_dataの数だけの配列。
} A;

とりあえず可変長のファイルの様ですね。
処理手順は以下の通りです。
(1)まず先頭4バイトを読んでi_dataを得ます。
(2)次にi_dataをエンディアン変換して、読み込む繰り返し数を得ます。
(3)メモリを繰り返し数x構造体のサイズでmallocします。
(4)一気に確保したメモリにファイルの残りを読み込みます。
(5)d_dataを一気にエンディアン変換します。
(6)情報をprintfの書式で加工して表示します。
で良いかと思います。

1.ポインタやcastを使いこなせますか?
>普通に使っていると思います(ダブルポインタ以上はアヤシイです)。
サンプルで書いたのが理解できたのであれば問題ないと思います。

2.shortやint型が何バイトのデータかわかりますか?
>自分の周りの計算機は、int型は32ビットばかりです。
shortが2バイトとfloatが4バイトと言う事が理解できていれば問題ないです。

3.エンディアンという言葉を知っていましたか?
>バイトオーダーは定性的には知っています(HP-UX→Linuxで変換が必要なんですよね)。どっちがどっちだったかは、今覚えておりません。
エンディアン変換は、4バイトのデータをunsigned char[4]にcastして、[0]⇔[3]と[1]⇔[2]の交換を行うか、unsigned intにcastしてシフト演算とビット演算で同様になるように演算します。
参考↓
http://docs.hp.com/ja/B2355-90951/ch02s10.html

4.charが数値型でかつ文字型であることを知っていますか?
>charで「A」は数値の65に相当する、という意味でよいのでしょうか。
はい、合ってます。

5.'A'を16進や10進で書くと、どの値になるかわかりますか?
>わかりません。
上ので合ってるんですが勘違いかな?
'A'==0x41==65
ですね。

6.ワード境界やバウンダリと言う言葉を知って理解していますか?
>知りません。

下記のプログラムを見てください。
int main()
{
struct {
short a;
int b;
} A;

printf( "struct size=%d\n", sizeof(A) );
return 0;
}
cygwinのgccでコンパイルして実行すると
struct size=8
と表示されます。
でもshort+intですから6バイトですよね?
これがアライメントとかワード境界とかバウンダリと呼ばれるもので、int型は強制的に4バイト境界のアドレスから始まります。コンパイルオプションでバイト境界に変更することは可能ですが普通は余りやりません。
先ほどの構造体は、
struct {
short a;
short dummy;
int b;
} A;
間にshort dummyがあると考えてください。
コンパイラが勝手に挿入するので普通は気づきませんが、構造体をそのままファイルに出力すると受け取り側で問題になったりします。
ファイルに書き出す構造体を書くときは常に4バイト境界を意識しましょう。今回は4バイト境界を気にするデータはないんで関係ないんですけどね。
    • good
    • 0
この回答へのお礼

ご回答をじっくり読ませていただきました。(今は夏休みなので確認できませんが)お蔭様でうまく変換できそうです。エンディアン変換も未経験ですが、ご解説いただいて、すべきことがわかりました。まだまだ勉強しなければいけないことが山のようにありますが、良いエンジニアになれるよう、頑張ります。本当にありがとうございました。

お礼日時:2007/08/13 21:46

回答者no.1 zwiです。


代わりに私が答えますと、
例に書いた簡単な画像データ。
・0バイト目から4バイトが数値である。Xサイズを表す。
・4バイト目から4バイトが数値である。Yサイズを表す。
・8バイト目から4バイト毎に1ピクセルのデータである。X*Yサイズ分のピクセルデータがある。
を処理するプログラムは、

#include <stdlib.h>
#include <string.h>
int main(){
FILE *fp;
char str[2048];
int x,y,i;
fp = fopen( "binary_file", "r");
if( fp != NULL ){
fread( str, 2048, 1, fp );
}
fclose(fp);
if((fp = fopen("text_file", "w+")) == NULL){
printf("file error\n");
exit(1);
}
//X,Yサイズ
x = *(int*)(&str[0]);
y = *(int*)(&str[4]);
fprintf(fp, "Xサイズ=%d\n", x);
fprintf(fp, "Yサイズ=%d\n", y);
//各ピクセル
for( i=0 ; i<(x*y) ; i++ ) {
fprintf(fp, "ピクセル=%08x\n", *(unsigned int*)(&str[8+i*4]));
}
fclose(fp);
}
あまりメンテナンス性のよい書き方ではないですが参考というとで。多少エラー処理で気になる部分は保留しました。
こんな感じでポインタや各データ形式のメモリ上の状態に関する知識がなくてはプログラムを作れません。
さらに、ややこしいのはINTEL系ではないPOWER-MACの数値データはビックエンディアンという形式のためINTEL系のリトルエンディアン形式への変更も必要とします。

逆に質問します。
今回表示しようとしてるバイナリデータのフォーマットをお持ちでしたら格納されているデータ形式の種類を教えてください。ファイルを作ったパソコンの種類も教えてほしいです。

それと、どこまでの知識があるか質問させてください。
1.ポインタやcastを使いこなせますか?
2.shortやint型が何バイトのデータかわかりますか?
3.エンディアンという言葉を知っていましたか?
4.charが数値型でかつ文字型であることを知っていますか?
5.'A'を16進や10進で書くと、どの値になるかわかりますか?
6.ワード境界やバウンダリと言う言葉を知って理解していますか?
以上です。
フォーマットと知識から可能なプログラムの作り方を考えてみますので、回答お待ちしています。

この回答への補足

本当に何度もご回答いただき、申し訳ありません。例で書いていただいたコードも大まかには理解できました。データは以下のような感じです(要素数が多いので簡略化しました)。
struct{
int i_data;
char s_data[32][16];
float d_data[32];
}A;
i_dataが一連のデータのインデックスになっていて、i_dataの分だけs_dataとd_dataが繰り返されます。もらったデータはHP-UXで作られていて、Linux上で出力しようとしています(HP-UX上で作ったデータをメール添付でもらって、添付ファイルを一旦Windowsに落としてから、FTP(バイナリモード)でLinux上に持って来ています。

あと、私の知識は以下の通りです(大変お恥ずかしいですが…)。
1.普通に使っていると思います(ダブルポインタ以上はアヤシイです)。
2.自分の周りの計算機は、int型は32ビットばかりです。
3.バイトオーダーは定性的には知っています(HP-UX→Linuxで変換が必要なんですよね)。どっちがどっちだったかは、今覚えておりません。。
4.charで「A」は数値の65に相当する、という意味でよいのでしょうか。
5.わかりません。
6.知りません。

すみませんが、よろしくお願い致します。

補足日時:2007/08/12 23:52
    • good
    • 0

回答者no.1 zwiです。


極論を言うとテキストファイルは文字と改行などの制御コードだけで構成されたバイナリデータです。ですから、バイナリデータに文字が混ざることは不思議でもなんでもありません。
一般的にバイナリデータと呼ばれるものは、整数値、浮動小数点値、文字、文字列などがフォーマットに従って格納されているデータファイルことを言います。
バイナリデータを自動的に解析する方法はありませんので、バイナリデータ格納フォーマットを知っている必要があります。
フォーマットとは、例えば簡単な画像データだと。
・0バイト目から4バイトが数値である。Xサイズを表す。
・4バイト目から4バイトが数値である。Yサイズを表す。
・8バイト目から4バイト毎に1ピクセルのデータである。X*Yサイズ分のピクセルデータがある。
となります。

C言語で処理する場合、構造体にロード可能な場合はそのまま構造体にロードして、構造体のメンバを各々printfで形式に合わせて表示させる必要があります。
構造体にロードが不可能な場合は、1バイト1バイトづつフォーマットに従って変換をかけてprintfで表示させてやらないとできません。
どちらも、それなりの知識を必要とします。
    • good
    • 0
この回答へのお礼

度々ご回答いただき、ありがとうございます。対象ファイルは、元々データチェック用のダンプファイルで、ある構造体がそのまま入っているようです。ですのでこの場合は、たぶん構造体にロードできるのですよね。
もうひとつご回答下さっているようですので、詳細は次に書かせていただきます。

お礼日時:2007/08/12 23:51

そもそもテキストファイルとは文字データだけで構成されかつ


基本的にどのような機種のHW(PC)でも共通して利用できる
ファイルで、それ以外はバイナリファイルと呼びます。

もちろんバイナリファイルは、文字コードなども意識していませんので
通常アプリケーションが都合のいいようにファイルを作ります。
つまり、読み込む=ファイルが理解できるではありません。
障害なくその(バイナリ)ファイルを使うには、
そのファイルのフォーマット(形式・構造)を理解したうえで
使わなければならないのです。

上記の事をまず頭において下さい。

>今度はfprintf()で出力すればどうなりますか?
ファイルの中身になにが入っているかわからないので、
なにが起こるかわかりません。

>バイナリファイルが読めるでしょうか?
読み込みは可能。
ただし、テキストとして理解しているわけではなく、
本当にただのデータの羅列として読み込んだだけ。

>バイナリファイルじゃないですよね?
文字コードを意識していない時点でテキストファイルではないので
バイナリファイルです。
    • good
    • 0
この回答へのお礼

お礼が遅くなり、申し訳ありません。早速のご回答、ありがとうございました。テキストとバイナリのご説明は理解しやすかったです。バイナリデータを読み込んで、読み込んだデータからデータ構造にしたがって各パラメータに代入してやり、fprintfで各パラメータを出力する、といったことでできるのでしょうか。ご参考までに、no.3の方のお礼に基本のコードを書きましたので、ちょっと見ていただけますと幸いです。

お礼日時:2007/08/11 11:12

>今度はfprintf()で出力すればどうなりますか?


一概には言えませんがデータが壊れるというか、NULLが含まれていると途中までしか出力されないでしょう(読んだデータをそのまま出力するとして)
>訳のわからないものが見える
極端な言い方をすると、テキストエディタで開いてみて、訳のわからないモノが表示される(可能性がある)ファイルをバイナリデータと呼びます
(文字コード違いで、文字化けしているってのは除く)

テキストファイルに変換して利用するなら、ファイルをくれた人にどんなフォーマットになっているか、聞いた方がいいと思います
そのまま出力していい部分は何もしなくてもいいですが、バイナリ(多分数値データ)を人がわかる形式に変換して出力必要があると思いますが…
    • good
    • 0
この回答へのお礼

お礼が遅くなり、どうもすみません。早速のご回答、ありがとうございました。NULLまでしか表示されないのでしょうか。。。
サンプルコードを作ってみたのですが、strの中を、各データのフォーマットに分解する、といった感じでよろしいのでしょうか。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
FILE *fp;
char str[2048];
fp = fopen( "binary_file", "r");
if( fp != NULL ){
fread( str, 2048, 1, fp );
}
fclose(fp);
if((fp = fopen("text_file", "w+")) == NULL){
printf("file error\n");
exit(1);
}
fprintf(fp, "%s\n", str);
fclose(fp);
}

お礼日時:2007/08/11 10:58

C言語は良く判らないので、まともな回答はできませんが、


バイナリファイルはバイナリエディタで開かないと、まともには
見えません。
バイナリエディタをいれましょう。

※Perlなら、簡単に処理できるんですが・・・
    • good
    • 0
この回答へのお礼

お礼が遅くなり、どうもすみません。早速のご回答、ありがとうございました。バイナリエディタで開いて、文字コードを調べていって人間が理解する…ということなのでしょうか。おかしなことを言っていましたらすみません。

お礼日時:2007/08/11 10:32

まず間違いなくバイナリデータです。


文字が読めるのは、バイナリデータ中に文字が埋め込まれているからです。
不十分な知識でプログラムを作るよりも、バイナリエディタを使ったほうが簡単にテキスト化(16進数のダンプ)にできます。
こちらをどうぞ。
http://www.vector.co.jp/soft/win95/util/se079072 …

その不十分な知識で、バイナリデータを何に使うかが疑問ですが。
これで問題が解決すれば幸いです。
    • good
    • 0
この回答へのお礼

お礼が遅くなり、どうもすみません。早速のご回答、ありがとうございました。不十分な知識でやりたいことは、バイナリデータの内容をテキスト化して、人間が理解できるようにすることです。(上記のバイナリエディタを紹介したのですが、結局「わからない」と言われてしまいまして…)
バイナリデータ中に文字を埋め込む技術というものを知りませんでした。
ご指摘どうもありがとうございました。

お礼日時:2007/08/11 10:10

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