MemoryStreamの異サイズ分割

解決


デル吉  2009-12-03 22:53:47  No: 36384

(D5)TMemoryStreamの取り扱いで質問です。

複数のファイル(F1, F2, F3, ...., Fn)から、サイズの異なるデータを相次いでメモリストリームに読み込み、これをファイル(Fo)として出力する。

今度は、別のアプリで、Foを読み込み、元々のサイズごと分割して、最初のファイル(F1, F2, F3, ...., Fn)に復元する、という処理を考えています。

seekとかCopyFromメソッドを使えば良さそうだ、ということは理解できたのですが、読み込み元のファイルサイズをどうやって保持すればいいかというのが解決できません。
全てが同じサイズであれば十兵衛さんのSeparateStreamでいいのですが...

何かいい知恵がありましたら、ご教授願います。


ぽむぽむ  2009-12-03 23:33:11  No: 36385

書き込み
1)FoにF1ファイルのサイズをIntegerで書き込む
2)FoにF1ファイルの内容を書き込む(CopyFromでいいのかな?)
3)FoにF2ファイルのサイズをIntegerで書き込む
4)FoにF2ファイルの内容を書き込む
・・・

読み込み
1)Integerを読み込みサイズを得る
2)1)で得たサイズ分をFoから読み込み、ファイルに保存する(F1)。
3)Integerを読み込みサイズを得る
4)3)で得たサイズ分をFoから読み込み、ファイルに保存する(F2)。
・・・

とか?


デル吉  2009-12-04 00:57:59  No: 36386

ぽむぽむさん、早速の回答、ありがとうございます。

それですと、1)、3)で「サイズが記録されている部分のサイズ」が分からないと2)、4)の処理ができないのではないでしょうか。


デル吉  2009-12-04 00:58:45  No: 36387

すみません、上記は、読み込み時の場合です。


だから...  2009-12-04 01:31:15  No: 36388

>それですと、1)、3)で「サイズが記録されている部分のサイズ」が分からないと2)、4)の処理ができないのではないでしょうか。
書き込み時にそれぞれのサイズDATAを4Byte(Integerのサイズ)でStreamに書き込んでいるんだから、
読み込み時にはそのサイズDATA(4Byte分)を読み込めばいいの。


茶柱  2009-12-06 20:21:22  No: 36389

ぽむぽむさん、だから...さんの仰っているのは
ファイルの中身を書き出す前に、そのサイズを保存しておけばOKということです。

procedure PackStream(fi: TStream; fo: TStream);
var
    iSize: INT64;
begin
    iSize := fi.Size;
    fo.WriteBuffer(iSize, SizeOf(iSize));    //←ここでサイズを保存しておく
    fo.CopyFrom(fi, 0);   //←CopyFrom(fi, iSize)でも一緒
end;
procedure RestoreStream(fi: TStream; fo: TStream);
var
    iSize: INT64;
begin
    fi.ReadBuffer(iSize, SizeOf(iSize));    //←ここでサイズが分かる
    fo.CopyFrom(fi, iSize);    //←サイズ分Streamから読み込む
end;

こういうのを作っておいて、結合するときはPackStreamをファイル数だけ読み、
展開するときはRestoreStreamをその数だけ呼べばファイルサイズが分かるということです。

ファイル数が固定ならこれで十分かもしれませんが、不定なら
出力する前にファイル数も入れておくと良いかもしれませんね。

intFileCount = ?←どこかでファイル数が分かる
    fo.WriteBuffer(intFileCount, SizeOf(FileCount));
こうしてから、PackStreamをループして呼び出す。

展開するときは
    fi := TFileStream.Create(マージしたファイルのパス, fmOpenRead)
    fi.ReadBuffer(intFileCount, SizeOf(FileCount));   //←内包しているファイルの数が分かる
    for i:=0 to intFileCount-1 do 
    begin
        strPath := パスの生成
        fo := TFileStream.Create(strPath, fmCreate);
        PackStream(fi, fo);
        fo.Free;
    end;
    fi.Free;

いかがでしょうか。

(動作未確認です)


デル吉  2009-12-21 19:04:28  No: 36390

お返事が遅くなりまして、申し訳ありません。皆さん、どうもありがとうございました。

茶柱さんのおっしゃるとおりのソースで実現できました。

本当に助かりました!!


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加