あるバイナリファイルに存在する特定のバイナリブロックを置換する
ために、対象ファイルをMemoryStreamなどに読み込んで、検索し、
ある一定の連続するバイト(3C 7E 90 C8 21 … など)と一致したら
それを置換するようにしたいと思っています。
てっきりTStreamにはFind系のメソッドが存在すると思っていたの
ですが、存在を確認できなかったため、しょうがなく1バイトずつ
ループで回して検索しているのですが、1MBのファイルを検索する
のに数分かかってしまっています。
チェック対象のファイルサイズや位置が固定されていれば、seek
して指定位置を置き換えればよいだけなのですが、これらが可変
のため、少々難儀しております。
できればDelphiに最初からある方法でこれを解決したいのですが、
やはり自力でBM法などのルーチンを書いてクリアするしかないの
でしょうか?
一度String型などに変換して、StringReplaceをかけるなどの方法も
考えたのですが、うまく行きませんでした。
少しでもアドバイスをいただけると幸いです。
> やはり自力でBM法などのルーチンを書いてクリアするしかないの
でしょうか?
それしかないんじゃないでしょうか?
いちおうFDelphi(http://www.nifty.ne.jp/forum/fdelphi/)というサイトの
サンプル蔵にBM法を使った単一文字検索、複数文字検索のクラスがあります。
それを使って、見つかった部分を置き換えて、次へ…という方法でどうでしょう?
高速化のキーワードとしては
・バッファリング
・ポインタでいじくる
かな?
バッファリングに関してはサイト発見。
http://www.asahi-net.or.jp/~HA3T-NKMR/tips020.htm
アドバイスありがとうございます。
>たかみちえ さま
ご提示いただいたサンプルは存じていたのですが、内部処理が
アセンブラなので使用を躊躇しておりました。
ただ、分からないなりにアセンブラ部を見てみると、どうも検索
対象がアスキー文字列のみではないようなので、「これはいける!」
と思って実際に組み込んでみました。
しかし、検索対象ファイルがバイナリなので、PCharにキャストした
時点で$0以下のデータが切り捨てられてしまい、検索できません
でした。
とりあえずこのコードを参考に、バイナリに対応できるよう、考えて
みたいと思いますが、私の頭ではなかなか難しいです。
>None さま
バッファリングに関しては、以下のコードで一括ロード/アクセス
できると思っていたのですが、ShowMessageで長さを取ってみると
確かに長さが足りないですね。
ということは、ヘルプが間違っているのでしょうか・・・?
procedure TForm1.Button1Click(Sender: TObject);
var
ims: TmemoryStream;
PS: ^String;
S: String;
begin
ims := TMemoryStream.Create;
ims.LoadFromFile('C:\test.dat');
PS := @ims.Memory;
ShowMessage(IntToStr(PS^));//
SetLength(S, Length(PS^) * 2);
BinToHex(PChar(PS^), PChar(S), Length(PS^));
RichEdit1.Lines.Text := S;
ims.Free;
end;
ちなみにDelphi6PROを使用しております。
すみません、上記のコードは以下のミスです。
>ShowMessage(IntToStr(PS^));//
ShowMessage('size:'+IntToStr(Length(PS^)) + #13#10 + 'filesize:' + IntToStr(ims.Size));
ファイルサイズが600KB程度あるにもかかわらず、size:で表示される
のは11KB程度です。なぜでしょうか。。。
すみません、何度も自己レスなのですが、上のコードは単に
String(長い文字列型)に制御コードが入っているからStringとして
扱われないというだけですね。
(その証拠にims.Size には正常な値が入っておりますし・・・)
格納先をarray of Byteなどに変更するようにしてみます。
ツイート | ![]() |