yTakeです。
度々お世話になりっています。
今回は基本的なことですが、バイナリーデータをファイルへ書き出す方法に付いてです。
"BlockWrite"を使いたいと思います。次ぎの2例を試しましたが、いずれも思う様に動作していません。
テスト1は、WordデータをByteに分割してバイト配列に格納し、"BlockWrite"で書き出します。
テスト2は、Wordデータをそのままワード配列に格納し、2Byte単位で"BlockWrite"で書き出します。
procedure test1();
var
wid, hei, dpx, dpy, cnt : Word;
buf : Array of Byte;
fname : String;
bf : File;
begin
wid := getTAG( $256 );
hei := getTAG( $257 );
dpx := getTAG( $258 );
dpy := getTAG( $259 );
SetLength( buf, 20 );
AssignFile( bf, filename );
ReWrite( bf, 1 );
buf[ 0 ] := 0; buf[ 1 ] := 0;
buf[ 2 ] := $00FF and wid; buf[ 3 ] := $00FF and ( wid shr 8 );
buf[ 4 ] := $00FF and hei; buf[ 5 ] := $00FF and ( hei shr 8 );
buf[ 6 ] := 0; buf[ 7 ] := 0;
buf[ 8 ] := $00FF and dpx; buf[ 9 ] := $00FF and ( dpx shr 8 );
buf[ 10 ] := $00FF and dpy; buf[ 11 ] := $00FF and ( dpy shr 8 );
buf[ 12 ] := $00FF and wid; buf[ 13 ] := $00FF and ( wid shr 8 );
buf[ 14 ] := $00FF and hei; buf[ 15 ] := $00FF and ( hei shr 8 );
buf[ 16 ] := 0; buf[ 17 ] := 0; // EPSON MAXD
buf[ 18 ] := 0; buf[ 19 ] := 0;
BlockWrite( bf, buf, 20, cnt );
CloseFile( bf );
end;
procedure test2();
var
wid, hei, dpx, dpy, cnt : Word;
buf : Array of Byte;
fname : String;
bf : File;
begin
wid := getTAG( $256 );
hei := getTAG( $257 );
dpx := getTAG( $258 );
dpy := getTAG( $259 );
SetLength( buf, 10 );
AssignFile( bf, filename );
ReWrite( bf, 2 );
buf[ 0 ] := 0;
buf[ 1 ] := wid;
buf[ 2 ] := hei;
buf[ 3 ] := 0;
buf[ 4 ] := dpx;
buf[ 5 ] := dpy;
buf[ 6 ] := wid;
buf[ 7 ] := hei;
buf[ 8 ] := 0;
buf[ 9 ] := 0;
BlockWrite( bf, buf, 10, cnt );
CloseFile( bf );
end;
wid, heiは"592"、dpx, dpyは"150"なのですが、
この結果をバイナリエディタで確認すると、全く違うデータが書き込まれています。
何か使い方に間違いがあるからと思いますが、よく分かりません。
どなたか、ご教授願えればと思います。
なんでStream系のクラスを使わないのか?というのは置いといて、
まずBlockWriteを呼び出す時点でbufに正しい値が入っているかどうか確認してみてはいかがですか?
あとはBlockWriteの第2パラメータはbufではなくbuf[0]ではないかと。
んでもってtest2のbufがarray of Byteになってますけどarray of Wordでは?
いずれにせよもう古いファイル入出力ルーチンを使うのはやめましょう。
型無しvarパラメータに動的配列を渡すと、予期せぬ結果を引き起こす
ttp://srgia.com/docs/dbl/DelphiBugList0567.html
通りすがりさん
ありがとうございました。
大変参考になりました。
動的配列を使っていると言う意識が希薄でした。
BlockWriteの第2パラメータはbufではなくbuf[0]で解決です。
また、test2のbufがarray of Byteになってますけどarray of Wordでした。
実は、元々TFileStreamで始めたのですが、うまく行かず、色々試した中で上記をアップさせて頂いた次第です。
TFileStreamでも、buf[0]とする事で取り合えずうまく行きました。
ただ、納得が行かない点がありました。
動的配列は
buf : Array of Word;
としました。
wid := getTAG( $256 );
hei := getTAG( $257 );
dpx := getTAG( $258 );
dpy := getTAG( $259 );
buf[ 0 ] := 0;
buf[ 1 ] := wid;
buf[ 2 ] := hei;
buf[ 3 ] := 0;
buf[ 4 ] := dpx;
buf[ 5 ] := dpy;
buf[ 6 ] := wid;
buf[ 7 ] := hei;
buf[ 8 ] := 0;
buf[ 9 ] := 0;
SetLength( buf, 10 );
fs := TFileStream.Create( filename, fmCreate );
cnt := fs.Write( buf[ 0 ], 20 );
fs.Free();
で、全てのbufデータがファイルに期待通りに書き出されます。
疑問は、fs.Write( buf[ 0 ], 20 )のところです。
bufはwordの配列として定義したので、fs.Write( buf[ 0 ], 10 )で良いはずと思うのですが、これではbufの半分までしか書き出されません。
最終的にBlockWriteでうまくいった時は、
buf : Array of Byte
の時は、
BlockWrite( bf, buf[ 0 ], 20 )
buf : Array of Word;
の時は、
BlockWrite( bf, buf[ 0 ], 10 )
で、全てのbufデータがファイルに下記出されています。
考えられる相違は、TFileStreamで書き出しの単位の指定の方法が分かっていません。
BlockWriteの時は、ReWrite( bf, "書き出し単位" )と明示的に指定されました。
お蔭様でストリームで動作としてはOKとなりました。
ストリームでの書き出し単位いついてご教授頂ければ幸いです。
少なくとも
Delphi 5,6 のヘルプにもWriteメソッドの説明に「Count バイトを書き込む」と
の記載がありますが、ヘルプとかは、ご覧になっておられないのでしょうか?
通りすがりさん
ありがとうございます。
質問の意図が分かり難くてすみません。書き込みするバイト数の事ではありません。TFileStreamで書き込みの際の書き込み単位(表現がこれで良いか分かりません)
例えば、BlockWriteの例では、Byte配列の場合は書き込み単位はバイトになりますので、20バイトを書き込む場合には、BlocjWrite( buf[0], 20 )としますが、Word配列とした場合では、20バイトを書き込む場合にはBlockWrite( buf[0], 10 )となると思います。その際、ReWriteで、各々1、2を指定して書き込み単位を明示的に設定しています。
これと同様の書き込み最小単位の設定がTFileStreamでもある「のでしょうか?と言うのが、問い合わせの意図でした。
その様な設定はなく、書き込み最小単位は常にバイトと言う事ですね。
以下は本題とは関係ありませんが、
もちろん、ヘルプやweb上を探したりしています。
ただ、これまでヘルプはあまり役に立っていない様に感じます。
今回も、TFileStreamを当たってみましたが、"TFileStream"の他に"TFileStream.Create", "TFileStream.Destroy", "TFileStream.FileName"の3つしかみあたりません。
また、文字定数の意味を知りたいと思いヘルプを参照しても、例えば、TFileStream関連では、オープン時の"fmCreate"や"fmOpenWrite"などの種類と意味を調べたのですが、ヘルプには乗っていませんね。
XE3のメニューのヘルプから"DELPHIヘルプ"を呼び出しました。このヘルプとは別にあるのでしょうか?
参照にご案内頂けたオンラインヘルプが最も頼りになりそうです。
ネットなどはもっと良く調べればみつかったであろうとは思います。
ありがとうございました。
SizeOfを使いましょう。
fs.Write(buf[0],Length(buf) * SizeOf(Buf[0]));
あとステハンといえど紛らわしいのでそのあたりは配慮して>2番目以降の通りすがりさん
yTakeです
閉じた後でスミマセン。
本スレッドでは通りすがりさんは二人おられたのですね。
気付きませんでした。(普通気が付きませんよね)
最初の通りすがりさん、2番目の通りすがりさん、ありがとうございました。
結論としましては、書き込みの最小単位はコーディング者が具体的に知る必要はなく、最小単位を取得して関数等に渡せられればOKと言う事ですね。
ありがとうございました
> 例えば、TFileStream関連では、オープン時の"fmCreate"や"fmOpenWrite"などの種類と意味を調べたのですが、ヘルプには乗っていませんね。
http://docwiki.embarcadero.com/Libraries/XE3/ja/System.Classes.TFileStream.Create
XE3の環境は手元にないけれど、TFileStream.Createに説明ありますよ。
3人目の通りすがり?
ステハン使う時点で配慮もへったくれもありませんwww
俺にじゃなくて質問者にだっての。アホだな。
ツイート | ![]() |